Go 1.22 可能将改变 for 循环变量的语义
几乎世界上每个 Golang 程序员都踩过一遍 for 循环变量的坑,而这个坑的解决方案已经作为实验特性加入到了 Go 1.21 中,并且有望在 Go 1.22 中完全开放。
举个例子,有这么段代码:
1 | var ids []*int |
可以试着在 playgound 里面运行下:go.dev/play/p/O8MVGtueGAf
答案是:打印出来的全是 10。
这个结果实在离谱。原因是因为在目前 Go 的设计中,for 中循环变量的定义是 per loop 而非 per iteration。也就是整个 for 循环期间,变量 i 只会有一个。以上代码等价于:
1 | var ids []*int |
同样的问题在闭包使用循环变量时也存在,代码如下:
1 | var prints []func() |
根据上面的经验,闭包 func 中 fmt.Println(v),捕获到的 v 都是同一个变量。因此打印出来的都是 3。
在目前的 go 版本中,正常来说我们会这么解决:
1 | var ids []*int |
定义一个新的局部变量, 这样无论闭包还是指针,每次迭代时所引用的内存都不一样了。
这个问题其实在 C++ 中也同样存在: wandbox.org/permlink/Se5WaeDb6quA8FCC。
但真的太容易搞错了,几乎每个 Go 程序员都踩过一遍,而且也非常容易忘记。即使这次记住了,下次很容易又会踩一遍。...
剩余内容已隐藏