Golang之一个有趣的闭包问题

// 在论坛上看到一个有趣的闭包例子, 下面这两个例子输出结果截然不同 ... 
// 未达到目的
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)
}
//goroutines print: three, three, three
// 正确例子
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)
}
//goroutines print: one, two, three
// 还有第三个例子
func TestClosure2() {

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

    for _, v := range data {
        go func() {
            v.print()
        }()
    }
    //goroutines print: three, three, three

    // ---------------------------------
    // 解决方案 ... 
    // for _, v := range data {
    //  go func(x *field) {
    //      x.print()
    //  }(v)
    // }
    // ---------------------------------
    //goroutines print: one, two, three

    time.Sleep(3 * time.Second)
}
What you’ve discovered is another piece of syntactic sugar, whereby if you call a method that takes a pointer receiver on a value, then Go will automatically take the address of the value and use that as the receiver.

This has a subtle effect on your program. When the go statement evaluates v.print() if it needs a pointer receiver but does not have one, it takes the address of v, which as we saw before causes all of the go routines to work with the same copy of v.

If the go statement finds that it already has a pointer receiver, then it can use it directly as the receiver.

You can see this here with a modified version of your program that prints the address of field's receiver.

https://play.golang.org/p/wUXsuzdeI44

You can see that in TestClosure the address is different for the three invocations, it is in fact the address of the elements of []*field.