先看一下官网的原话 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会使用上一次循环结束时的值创造出来一个新的副本,来应用到新的循环中。