为什么用声明局部变量来实现golang范围运算符?

时间:2019-01-07 20:35:43

标签: go

当使用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的任何使用进行这种解释。如果对大型对象进行迭代,则该行为似乎更具可预测性,并且应该表现得更好(无需额外复制到局部变量)。

示例代码:

https://play.golang.org/p/y89nMxVgBEs

https://play.golang.org/p/qHnJXMuHKdJ

1 个答案:

答案 0 :(得分:4)

Go does not have reference variables

  

无法创建其中两个变量共享内存中相同存储位置的Go程序。可以创建两个变量的内容指向相同的存储位置,但这与共享相同存储位置的两个变量并不相同。

由于listint的一部分,而不是*int的一部分,所以不应期望value := list[i]的地址与该地址相同。 list[i]的地址。由于我们已经知道value是副本,并且以任何方式对其进行修改都不会影响list[i],因此一次为int分配内存的性能要高得多,并且在循环的每个迭代中都覆盖它,而不是在每个迭代中分配一个 new int并垃圾收集旧的。