for遍历中的go func

循环变量只是普通变量,每次循环只是重新赋值。

以下两种写法是等价的:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 写法 1
list := []string{"a", "b", "c"}
var i int
var v string
for i, v = range list {
fmt.Println(i, v)
}

// 写法 2
list := []string{"a", "b", "c"}
for i, v := range list {
fmt.Println(i, v)
}

循环变量 i 和 v 每次循环都会被重新赋值,并非生成新的变量。

这样就产生了一个问题:如果循环体中有并发操作(最常见的是for中起协程),并且并发中用到了 i 和 v,那么 i 和 v 很可能已经不是此次循环的值了,而是下次甚至是最后一次循环的值。

如果要保证协程中用到的循环变量一定就是此次循环的值,就需要 绑定循环变量,两种方式:

  • 协程传参
  • 在协程开始之前,新定义变量,将循环变量赋值给新变量,然后协程中使用新变量