3 different funcs launched as goroutines produce the same goroutine (apparently ignore arguments)

Issue

For 3 different and distinct “c”

for _, c := range u.components { // u.components has 3 members
    fmt.Printf("%v %v", c.name, c.channel) // prints 3 distinct name/channel pairs 
    go c.Listen(); // a method of c that listens on channel c.channel
}

…launches 3 identical goroutines in which c.name and c.channel are identical.

The long version (commented, short code):
https://play.golang.org/p/mMQb_5jLjm

This is my first Go program, I’m sure I’m missing something obvious. Any ideas?

Thank you.

Solution

The call to c.Listen() is closing around the value of c, which is passed via a pointer to Listen, and each iteration changes that value. It’s easier to visualize if you look at the method call as a method expression

go (*component).Listen(&c)

https://golang.org/doc/faq#closures_and_goroutines

Create a new value for c on each iteration to prevent the previous from being overwritten:

for _, c := range u.components { // u.components has 3 members
    c := c
    fmt.Printf("%v %v", c.name, c.channel) // prints 3 distinct name/channel pairs 
    go c.Listen(); // a method of c that listens on channel c.channel
}

Or use the value contained in the slice directly:

for i := range u.components {
    go u.components[i].Listen()
}

Answered By – JimB

Answer Checked By – Mary Flores (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.