Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return reference to struct in Go-lang

I am having some thought issues with the following code

package main

import (
    "fmt"
)

type Company struct {
    Name string
    Workers []worker
}

type worker struct {
    Name string
    Other []int
}

func (cmp *Company) NewWorker(name string) worker {
    wrk := worker{Name: name}
    cmp.Workers = append(cmp.Workers, wrk)
    return wrk
}

func main() {
    cmp := Company{}
    cmp.Name = "Acme"
    wrk := cmp.NewWorker("Bugs")
    for i := 1; i <= 10; i++ {
        wrk.Other = append(wrk.Other, i)
    }
    fmt.Println(wrk)
    fmt.Println(cmp)
}

https://play.golang.org/p/Bja7u148mg

As you can see the code is not returning the worker I am creating but a copy of it. How can I get it to return the actual worker? I have tried some variations of * and & on the different workers but I end up with either:

invalid indirect of worker literal (type worker)

or:

cannot use wrk (type worker) as type *worker in return argument

Any ideas on how to do this?

like image 902
Johan Avatar asked Aug 25 '16 14:08

Johan


People also ask

Does Golang pass struct by reference?

To be specific, Go does not support “Pass-By-Reference” semantic in any way. The reason is simple; Go does not support a reference variable as you have in other programming languages like C++.

Can you return a struct?

One of them asked if you could return a struct from a function, to which I replied: "No! You'd return pointers to dynamically malloc ed struct s instead."

How do you access a struct in Go?

Go struct access fields The struct fields are accessed with the dot operator. We create an empty User struct. We initialize the fields with values and read them using the dot operator.

Does Golang make return pointer?

Pointers in Go programming language or Golang is a variable which is used to store the memory address of another variable. We can pass pointers to the function as well as return pointer from a function in Golang.


1 Answers

func (cmp *Company) NewWorker(name string) *worker {
    wrk := worker{Name: name}
    cmp.Workers = append(cmp.Workers, wrk)
    return &wrk
}

& always means "take the address of" (except for the binary bitwise operator version). *, however, changes meaning depending on the context. The expression *Type means "pointer to Type". The express *Pointer means "the object that Pointer points to". This is why you get an invalid indirect of worker literal if you try to use the expression *wrk, because you're saying "give me the object that wrk points to", but wrk isn't a pointer.

As such, you need *worker as your return type (returning a pointer to a worker), and you return &wrk, the address of the structure you're returning.

Another alternative is to use the built in new() to create a pointer in the first place:

func (cmp *Company) NewWorker(name string) *worker {
    wrk := new(worker)
    wrk.Name = name
    cmp.Workers = append(cmp.Workers, *wrk)
    return wrk // wrk is a pointer here
}

All that said, there's little reason to return a pointer to your worker structure here. The structure itself only has two fields, both of which are already reference types (strings are essentially just immutable slices), so the entire structure is only 5 machine words long (so 20 or 40 bytes, depending on whether you're on 32bit or 64bit). You're not modifying the struct after return, and the version you store in the Company struct is also a copy (Company holds a slice of workers, not a slice of pointers to workers).

like image 174
Kaedys Avatar answered Oct 08 '22 22:10

Kaedys