Go循环指针行为差异原因及Go 1.22版本变更疑问
Go 1.19循环指针问题解答
问题1:两个for range循环结果差异的原因
第一个循环输出3 3 3的本质
在Go 1.19及更早版本中,for range迭代切片时,循环变量是复用的同一个内存地址。整个循环过程里,key始终是同一个变量,每次迭代只是把切片当前元素的值覆盖到这个变量上。
你在res[i] = task{key: &key}中保存的是这个复用变量的地址,当循环结束时,key的值已经被最后一个元素"3"覆盖,因此所有task的key指针都指向这个最终值,输出自然全是3。
对应代码片段:
keys := []string{"1", "2", "3"} res := make([]task, len(keys)) for i, key := range keys { res[i] = task{key: &key} // 所有task的key指向同一个复用变量的地址 }
第二个循环能正确输出的原因
第二个循环里,managers中的每个task.key指向的是外部独立定义的key1、key2的地址,这两个变量不属于循环变量,不会被复用覆盖。
当你迭代managers时,虽然循环变量manager也是复用的,但你复制的是manager的值(其中包含指向key1/key2的指针)到result中。这些指针指向的是固定的、不会被修改的外部变量地址,所以最终能正确输出111和222。
不管是用append还是直接赋值result[i] = manager,结果都正确,因为复制的指针指向的是独立变量,不受循环复用影响。
问题2:Go 1.22的行为修改
你的理解完全正确,Go 1.22对for range循环变量的行为做了根本性修改:每次迭代都会创建新的循环变量,不再复用同一个内存地址。
这意味着原来第一个循环的代码在Go 1.22中会直接输出1 2 3,不需要额外创建临时变量来规避问题。
Go 1.19下的修复方案
如果要在Go 1.19中让第一个循环输出正确结果,只需要在循环内部创建临时变量保存当前迭代值,再取临时变量的地址:
for i, key := range keys { tempKey := key // 每次循环生成新的临时变量,地址唯一 res[i] = task{key: &tempKey} }
内容的提问来源于stack exchange,提问作者Violetta
相关产品推荐
相关产品推荐

