go1.22 版本关于loopvar改动的理解
先看一下官网的原话 https://golang.google.cn/blog/go1.22 :
The long-standing “for” loop gotcha with accidental sharing of loop variables between iterations is now resolved.
简单来说就是循环时候的变量不再共享一个地址,官网给的demo不好观察其中的状况,我重新写了一个新的demo来演示
// demo 代码
type T struct {
i int
x *T
}
func main() {
var n = 0
for t := (T{}); t.i < 9; t.i++ {
fmt.Printf("i %d , x %v, tt %v\n", t.i, t.x, unsafe.Pointer(&t))
if t.x != &t {
t.x = &t
n += 1
}
}
fmt.Println(n)
}
在1.21版本的输出
i 0 , x <nil>, tt 0xc000bec0c0
i 1 , x &{1 0xc000bec0c0}, tt 0xc000bec0c0
i 2 , x &{2 0xc000bec0c0}, tt 0xc000bec0c0
i 3 , x &{3 0xc000bec0c0}, tt 0xc000bec0c0
i 4 , x &{4 0xc000bec0c0}, tt 0xc000bec0c0
i 5 , x &{5 0xc000bec0c0}, tt 0xc000bec0c0
i 6 , x &{6 0xc000bec0c0}, tt 0xc000bec0c0
i 7 , x &{7 0xc000bec0c0}, tt 0xc000bec0c0
i 8 , x &{8 0xc000bec0c0}, tt 0xc000bec0c0
1
在1.22版本的输出
i 0 , x <nil>, tt 0xc000014070
i 1 , x &{0 0xc000014070}, tt 0xc000014080
i 2 , x &{1 0xc000014080}, tt 0xc0000140a0
i 3 , x &{2 0xc0000140a0}, tt 0xc0000140c0
i 4 , x &{3 0xc0000140c0}, tt 0xc0000140e0
i 5 , x &{4 0xc0000140e0}, tt 0xc000014100
i 6 , x &{5 0xc000014100}, tt 0xc000014120
i 7 , x &{6 0xc000014120}, tt 0xc000014140
i 8 , x &{7 0xc000014140}, tt 0xc000014160
9
很明显,在 1.21 版本中,循环变量t的地址都是一样的 0xc000bec0c0
而到了 1.22 版本中,变量t的地址每次都不相同,而且能观察出来 t.x 的值在每次循环中都是上一次循环时变量t的地址。
证明在每一次新的循环中,变量t会使用上一次循环结束时的值创造出来一个新的副本,来应用到新的循环中。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。