当使用golang range
运算符和&
运算符的地址进行循环时,我们会得到一些意想不到的行为。
举个例子:
list := []int{1, 2}
pointerList := []*int{}
for _, value := range list {
pointerList = append(pointerList, &value)
}
fmt.Print(*pointerList[0], *pointerList[1])
// Prints: 2 2
这将打印2 2
,因为变量value
仅声明一次,并且每次迭代都会更改值(而value
的地址保持不变)。
问:为什么go编译器不会像将value
替换为list[i]
那样解释上述代码,就像这样:
list := []int{1, 2}
pointerList := []*int{}
for i := range list {
pointerList = append(pointerList, &list[i])
}
fmt.Print(*pointerList[0], *pointerList[1])
// Prints: 1 2
如果我没记错的话,可以对for循环中的range
的任何使用进行这种解释。如果对大型对象进行迭代,则该行为似乎更具可预测性,并且应该表现得更好(无需额外复制到局部变量)。
示例代码:
答案 0 :(得分:4)
Go does not have reference variables。
无法创建其中两个变量共享内存中相同存储位置的Go程序。可以创建两个变量的内容指向相同的存储位置,但这与共享相同存储位置的两个变量并不相同。
由于list
是int
的一部分,而不是*int
的一部分,所以不应期望value := list[i]
的地址与该地址相同。 list[i]
的地址。由于我们已经知道value
是副本,并且以任何方式对其进行修改都不会影响list[i]
,因此一次为int
分配内存的性能要高得多,并且在循环的每个迭代中都覆盖它,而不是在每个迭代中分配一个 new int
并垃圾收集旧的。