循环变量快照问题
正确的写法
package gos
import (
"fmt"
"testing"
)
func TestTs(t *testing.T){
lis := []int{1,2,5}
for _, i := range lis{
// 匿名函数中传入循环的值,避免循环变量快照问题
go func(a int){
fmt.Println("a: ", a)
}(i)
}
}
/*
结果(因为没有做waitGroup,所以打印的个数不确定!):
a: 1
a: 5
a: 2
*/
❗️匿名函数中的循环变量快照问题:上面这个单独的变量i是被所有的匿名函数值所共享,且会被连续的循环迭代所更新的。
当新的goroutine开始执行字面函数时,for循环可能已经更新了f并且开始了另一轮的迭代或者(更有可能的)已经结束了整个循环,所以当这些goroutine开始读取i的值时,它们所看到的值已经是slice的最后一个元素了。
在匿名函数中显式地添加i这个参数(也就是形参a),我们能够确保使用的i是当go语句执行时的“当前”那个i。
错误的写法
❗️不可以像这样写——“循环变量快照”问题:
package gos
import (
"fmt"
"testing"
)
func TestTs(t *testing.T){
lis := []int{1,2,5}
for _, i := range lis{
go func(){
// 如果匿名函数中没有任何参数,i是被所有匿名函数共享的!这样i会是最后一个值
fmt.Println("a: ", i)
}()
}
}
/*
结果(因为没有做waitGroup,所以打印的个数不确定!):
a: 5
a: 5
a: 5
*/