出于效率考虑,我们经常使用单个变量来循环迭代器。但在循环中,每次循环迭代中都会有不同的值,有时候会导致未知的行为。
in := []int{1, 2, 3}
var out []*int
for _, v := range in {
out = append(out, &v)
}
fmt.Println("Values:", *out[0], *out[1], *out[2])
fmt.Println("Addresses:", out[0], out[1], out[2])
输出
Values: 3 3 3
Addresses: 0xc000014188 0xc000014188 0xc000014188
在out这个slice中的元素都是3。
原因:在每次迭代中,v是单个变量(内存地址不变),所以每次迭代都采用新值将 v append 到 out切片中。
最简单的解决方法是将循环迭代器变量赋值到新变量中:
in := []int{1, 2, 3}
var out []*int
for _, v := range in {
v := v
out = append(out, &v)
}
fmt.Println("Values:", *out[0], *out[1], *out[2])
fmt.Println("Addresses:", out[0], out[1], out[2])
新的输出:
Values: 1 2 3
Addresses: 0xc0000b6010 0xc0000b6018 0xc0000b6020
在 goroutine 中使用循环迭代变量也会有相同的问题。
list := []int{1, 2, 3}
for _, v := range list {
go func() {
fmt.Printf("%d ", v)
}()
}
输出将是:
3 3 3
请注意,如果不使用 goroutine 运行该函数,则代码将按预期运行。