When I run this code with go run main.go
, then I see this output:
inner: {Bar:{Baz:xyz} BarPtr:0xc0000101e0}
outer: {Bar:{Baz:} BarPtr:<nil>}
I can not understand why when passing a pointer to a routine, then the struct created inside that routine can not be exposed outside via pointers.
I know I could use a channel to publish the structs created inside the Go routine, but the piece of code I am working on would require too much additional boilerplate code. I would like to use a Wait Group with pointers if possible, but I can not find a way so I am wondering if this is possible at all?
To me I should be able to expose an internal struct via a pointer, but I am not sure maybe the compiler silently ignores this, or am I failing to understand some fundamental features of Go?
package main
import (
"fmt"
"sync"
)
type Foo struct {
Bar Bar
BarPtr *Bar
}
type Bar struct {
Baz string
}
func main() {
foo := Foo{}
var wg sync.WaitGroup
// the real example has more routines, so I need a wait group
wg.Add(1)
go func(strct *Foo) {
defer wg.Done()
bar1 := Bar{
Baz: "xyz",
}
bar2 := Bar{
Baz: "abc",
}
ownFoo := Foo{
Bar: bar1,
BarPtr: &bar2,
}
fmt.Printf("inner: %+v\n", ownFoo)
strct = &ownFoo
}(&foo)
wg.Wait()
fmt.Printf("outer: %+v\n", foo)
}
The correct expression to set the foo
value through the pointer strct
is:
*strct = ownFoo
On the other hand, the expression
strct = &ownFoo
sets the strct
pointer to the address of ownFoo
and leaves the foo
value untouched.
Keep in mind that if you have a variable that is being accessed from multiple goroutines, and at least one of them is writing/modifying the variable, without proper synchronization your code is bound to hit a data race, regardless of whether the variable is accessed directly or through a local pointer or what have you.