Search code examples
pointersgostructgoroutine

How to make struct survive outside its Go routine when using pointers to external struct


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)
}

Solution

  • 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.