go for range slice and goroutine method invocation,the logic behind

Issue

The code is like the following:

package main

    import (
        "fmt"
        "time"
    )

    type field struct {
        name string
    }

    func (p *field) print() {
        fmt.Println(p.name)
    }

    func main() {
        data := []field{{"one"},{"two"},{"three"}}
        for _,v := range data {
            go v.print()
        }
        time.Sleep(3 * time.Second)
    }

I know that the code is wrong,because the for loop variable is reused in the for-range loop.

When the goroutine has got the chance to launch,the value of v might has been modified. so the print result will be "three,three,three".

But when we modify the data variable into another declaration as:

data := []*field{{"one"},{"two"},{"three"}}

the print result will be "one ,two,three".

I didn’t get the point of why. Does the pointer make any difference or any different mechanism is on this?

I read this from this article. But the poster didn’t not tell why. Or it’s just a incident the output is right.

Solution

In the first loop, v is the value of a field item. Because v is addressable, it is automatically referenced as the pointer receiver for the print() method. So v.print() is using the address of v itself, and the contents of that address is overwritten each iteration of the loop.

When you change the declaration to use a *field, v is now a pointer to a field value. When you call v.print() in this case, you are operating on the value that v points to, which is stored in data, and the overwriting of v has no effect.

Answered By – JimB

Answer Checked By – Mildred Charles (GoLangFix Admin)

Leave a Reply

Your email address will not be published.