The most obvious error in your code is that Inner.Run()
has a value-receiver, which means it gets a copy of the Inner
type. When you modify this, you modify the copy, and the caller won't see any change on the Inner
value.
So first modify it to have a pointer-receiver:
func (c *Inner) Run(value int) {
// ...
}
If a method has a pointer-receiver, the address (pointer) of the value the method is called on will be passed to the method. And inside the method you will modify the pointed value, not the pointer. The pointer points to the same value that is present at the caller, so the same value is modified (and not a copy).
This change alone may make your code work. However, the output of your program is non-deterministic because you modify a variable (field) from one goroutine, and you read this variable from another goroutine too, so you must synchronize access to this field in some way.
One way to synchronize access is using sync.RWMutex
:
type Inner struct {
m *sync.RWMutex
Value int
}
When you create your Outer
value, initialize this mutex:
o := new(Outer)
o.In.m = &sync.RWMutex{}
Or in one line:
o := &Outer{In: Inner{m: &sync.RWMutex{}}}
And in Inner.Run()
lock when you access the Inner.Value
field:
func (c *Inner) Run(value int) {
c.m.Lock()
c.Value = value
c.m.Unlock()
for {
c.m.RLock()
fmt.Println(c.Value)
c.m.RUnlock()
time.Sleep(time.Second * 2)
}
}
And you also have to use the lock when you access the field in Outer.Run()
:
func (c Outer) Run() {
go c.In.Run(42)
for {
time.Sleep(time.Second)
c.In.m.RLock()
fmt.Println(c.In)
c.In.m.RUnlock()
}
}
Note:
Your example only changes Inner.Value
once, in the beginning of Inner.Run
. So the above code does a lot of unnecessary locks/unlocks which could be removed if the loop in Outer.Run()
would wait until the value is set, and afterwards both goroutines could read the variable without locking. In general if the variable can be changed at later times too, the above presented locking/unlocking is required at each read/write.