func TestClosure() {
i:=1
go func() {
i++
}()
time.Sleep(time.Second) //如果这里不sleep,上面的协程还没来得及修改共享变量,下面输出1,
fmt.Print(i)//输出2,说明闭包是对同一变量的引用,而不是copy
}
type field struct {
name string
}
func (p *field) print() {
fmt.Printf("%s %p\n",p.name,p)
}
func TestClosure1() {
data := []field{{"one"}, {"two"}, {"three"}}
for _, v := range data {
go v.print()
}
time.Sleep(time.Second)
data1 := []*field{{"one"}, {"two"}, {"three"}}
for _, v := range data1 {
go v.print()
}
time.Sleep(time.Second)
//输出如下
//three 0xc0000101e0
//three 0xc0000101e0
//three 0xc0000101e0
//three 0xc0000a8040
//one 0xc0000a8020
//two 0xc0000a8030
//区别在于对data中每个元素调用print时,实际传入print的值是v的地址,在迭代的过程中
//这个地址指向的值一直在被更新,因此三次输出了最后一次更新的值
//而对data1中每个元素调用print时,实际传入print的是指针本身的值,即在三次迭代的过程中
//传入print的是三个不同的指针,分别指向data1中的每个元素,因此每次输出的值不同
}
func TestClosure2() {
data := []field{{"one"}, {"two"}, {"three"}}
for _, v := range data {
go func(){
v.print()
}()
}
time.Sleep(time.Second)
data1 := []*field{{"one"}, {"two"}, {"three"}}
for _, v := range data1 {
go func(){
v.print()
}()
}
time.Sleep(time.Second)
//输出如下
//three 0xc000090030
//three 0xc000090030
//three 0xc000090030
//three 0xc0000a0040
//three 0xc0000a0040
//three 0xc0000a0040
//与TestClosure1中的区别在于,go v.print()会立即解析v的值并传入协程的栈中
//而闭包只是共享了v,在协程开始执行之前,v的值已经被更新了多次,因此输出的均是最后一次更新的值
}