ISSUE

在之前一次工作中,我遇到了一个go的循环变量作用域问题,当时困扰了我很久,在此记录一下。具体情况请看下面的代码

1
2
3
4
5
6
7
8
9
10
import "fmt"
var arr []*int
func main() {
for i := 0; i < 10; i++ {
arr = append(arr, &i)
}
for _, val := range arr {
fmt.Println(*val)
}
}

理论上,我们希望得到的是arr={0,1,2,3,4,5,6,7,8,9},但是实际上我们得到的是arr={9,9,9,9,9,9,9,9,9,9}

这是因为go使用for i:=0创建的循环变量i从始至终都是一个实例,而不是每次都创建新实例,这就导致了在循环体中&i从始至终都是同一个地址,然后不断被覆盖(循环时,arr={1},arr={2,2},arr={3,3,3}….这样)

SOLVE

解决方法也很简单,我们可以显示给它创建新实例,添加i:=i

1
2
3
4
5
6
7
8
9
10
11
import "fmt"
var arr []*int
func main() {
for i := 0; i < 10; i++ {
i:=i
arr = append(arr, &i)
}
for _, val := range arr {
fmt.Println(*val)
}
}

还有一种方式就是使用闭包解决

1
2
3
4
5
6
7
8
9
10
11
12
13
import "fmt"
var arr []*int
func main() {
for i := 0; i < 10; i++ {
func(x int) {
arr = append(arr, &x)
}(i)
}

for _, val := range arr {
fmt.Println(*val)
}
}