golang中的for循环值语义

golang中的for循环值语义,go,Go,关于进入SO的第一个问题。下面的代码显示,n在每次迭代中具有相同的地址。我知道这样一个for循环被一些人称为值语义,实际范围是切片的副本,而不是实际切片本身。为什么每个迭代中的n都有相同的地址?这是因为切片中的每个元素都被复制,而不是整个切片被预先复制一次。如果只复制原始片中的每个元素,那么在每次迭代中可以重用单个内存地址 包干管 import ( "fmt" ) func main() { numbers := []int{1, 2} for i,

关于进入SO的第一个问题。下面的代码显示,n在每次迭代中具有相同的地址。我知道这样一个for循环被一些人称为值语义,实际范围是切片的副本,而不是实际切片本身。为什么每个迭代中的n都有相同的地址?这是因为切片中的每个元素都被复制,而不是整个切片被预先复制一次。如果只复制原始片中的每个元素,那么在每次迭代中可以重用单个内存地址

包干管

import (
    "fmt"
)

func main() {
    numbers := []int{1, 2}
    for i, n := range numbers {
        fmt.Println(&n, &numbers[i])
    }
}
go游乐场的示例结果:

0xc000122030 0xc000122020
0xc000122030 0xc000122028
围棋维基有一个关于这个确切问题的讨论。它还解释了如何在实际代码中避免此问题。快速的答案是这样做是为了提高效率,而与切片无关
n
是一个单一变量/内存位置,在每次迭代时为其分配一个新值


如果您想进一步了解为什么会发生这种情况,请看一看。

您的问题有点错,它不是正在迭代的切片的副本。在Go中,当您传递一个片时,您实际上传递了一个指向内存的指针以及该内存的大小和容量,这称为片头。头被复制,但复制指向相同的底层内存,这意味着当您将
[]int
传递给函数时,更改该函数中的值,外部代码中原始
[]int
中的值也将更改

这与像
[5]int
这样按值传递的数组形成对比,这意味着当您传递它时,它实际上会被复制。在Go结构中,字符串、数字和数组按值传递。片实际上也按值传递,但如上所述,在这种情况下,包含指向内存的指针。传递指针的副本仍然可以更改指向的内存

现在来看看你的实验:

对于i,n:=范围编号

将在循环开始之前创建两个变量:整数
i
n
。在每个循环迭代中,
i
将递增1,
n
将被分配
数字[i]
的值(即整数值的副本)

这意味着实际上只有两个变量
i
n
。它们是相同的,这是您在输出中看到的


数字[i]
的地址是不同的,当然,它们是数组中项目的内存地址。

“为什么每次迭代中的n都有相同的地址?”这就是语言的工作原理。您有两个变量i和n,它们在每次迭代中都会更改它们的值(而不是它们的标识)。与slice或任何范围无关。
&n
是本地循环变量
n
的地址,它不会随每次迭代而更改。它不是片中元素的地址。“它不是正在迭代的片的副本”。我认为这在问题所问的意义上是正确的,但在更字面的意义上,“切片”(通常称为“切片头”)似乎是在迭代开始时复制的:另一个实验确定了我的想法并回答了问题。我有点困惑,因为在围棋教程中,作者说在循环开始之前复制整个片段,然后我看到每个
n
都有相同的地址,这意味着不可能复制整个片段。@HymnsForDisco嗯,看到两个实验很有趣,这也与我更新的想法相反:D,所以并不是在迭代过程中复制切片中的每个元素;该切片在迭代开始之前就被复制了?@HymnsForDisco谢谢!我认为你的评论是我从这个问题中得到的最有用的信息。