如果在循环中切片增加,你将如何迭代切片?

huangapple go评论85阅读模式
英文:

How will iterate over a slice if that slice increases inside the loop?

问题

当我在幻灯片上迭代for循环时(下面的代码),我得到的输出是0A,1M,2C

代码:

x := []string{"A", "B", "C"}

for i, s := range x {
    print(i, s, ",")
    x[i+1] = "M"
    x = append(x, "Z")
    x[i+1] = "Z"
}

为什么输出结果会是这样,而不是0A, 1Z, 2Z

阅读文档后,我发现切片是通过指向其基础数组的指针传递给函数的。

切片在for循环中也是通过指针传递的吗?(在文档中找不到原因)

如果是这样,我猜测输出结果为0A, 1M, 2C的原因是,初始时切片是通过指针传递给循环的,当切片的容量在循环的第一次迭代中加倍时,print(i, s)的值仍然基于基础数组打印。这样理解对吗?

英文:

When I iterate through the for loop on the slide (code below), I get the output Output: 0A,1M,2C,

code:

x := []string{"A", "B", "C"}

for i, s := range x {
	print(i, s, ",")
	x[i+1] = "M"
	x = append(x, "Z")
	x[i+1] = "Z"
}

Why is the output exactly like that and not 0A, 1Z, 2Z?

Reading the documentation, I saw that the slice is passed to the function by a pointer to the array it is based on.

Is the slice also passed to the for loop by pointer? (couldn't find why in the documentation)

If so, my guess as to why the output is exactly 0A, 1M, 2C, - because, originally, the slice was passed to the loop by pointer, and when the capacity of the slice is doubled in the first iteration of the loop, the print(i, s) values are still printed based on the base array. Is this true?

答案1

得分: 1

append可以分配一个新的数组。在第一个append之后,x现在是一个副本,你正在循环遍历原始数组。对x的更改现在不会影响s

让我们在循环中添加一些调试信息来查看。

x := []string{"A", "B", "C"}

for i, s := range x {
    fmt.Printf("Start: i=%v s=%v x=%p %v\n", i, s, x, x)
    x[i+1] = "M"
    fmt.Printf("After x[i+1] = \"M\": i=%v s=%v x=%p %v\n", i, s, x, x)
    x = append(x, "Z")
    fmt.Printf("After Append: i=%v s=%v x=%p %v\n", i, s, x, x)
    x[i+1] = "Z"
    fmt.Printf("After x[i+1] = \"Z\": i=%v s=%v x=%p %v\n\n", i, s, x, x)
}

结果如下:

Start: i=0 s=A x=0xc0000161b0 [A B C]
After x[i+1] = "M": i=0 s=A x=0xc0000161b0 [A M C]
After Append: i=0 s=A x=0xc000062180 [A M C Z]
After x[i+1] = "Z": i=0 s=A x=0xc000062180 [A Z C Z]

Start: i=1 s=M x=0xc000062180 [A Z C Z]
After x[i+1] = "M": i=1 s=M x=0xc000062180 [A Z M Z]
After Append: i=1 s=M x=0xc000062180 [A Z M Z Z]
After x[i+1] = "Z": i=1 s=M x=0xc000062180 [A Z Z Z Z]

Start: i=2 s=C x=0xc000062180 [A Z Z Z Z]
After x[i+1] = "M": i=2 s=C x=0xc000062180 [A Z Z M Z]
After Append: i=2 s=C x=0xc000062180 [A Z Z M Z Z]
After x[i+1] = "Z": i=2 s=C x=0xc000062180 [A Z Z Z Z Z]

注意,在第一个append之后,x的地址发生了变化。任何x[i+1] = ?的更改都不再影响s

英文:

append can allocate a new array. It does. After the first append, x is now a copy and you're looping over the original. Changes to x now have no affect on s.

Let's mark up the loop with some more debugging to see.

x := []string{"A", "B", "C"}

for i, s := range x {
    fmt.Printf("Start: i=%v s=%v x=%p %v\n", i, s, x, x)
    x[i+1] = "M"
    fmt.Printf("After x[i+1] = \"M\": i=%v s=%v x=%p %v\n", i, s, x, x)
    x = append(x, "Z")
    fmt.Printf("After Append: i=%v s=%v x=%p %v\n", i, s, x, x)
    x[i+1] = "Z"
    fmt.Printf("After x[i+1] = \"Z\": i=%v s=%v x=%p %v\n\n", i, s, x, x)
}

And the result...

Start: i=0 s=A x=0xc0000161b0 [A B C]
After x[i+1] = "M": i=0 s=A x=0xc0000161b0 [A M C]
After Append: i=0 s=A x=0xc000062180 [A M C Z]
After x[i+1] = "Z": i=0 s=A x=0xc000062180 [A Z C Z]

Start: i=1 s=M x=0xc000062180 [A Z C Z]
After x[i+1] = "M": i=1 s=M x=0xc000062180 [A Z M Z]
After Append: i=1 s=M x=0xc000062180 [A Z M Z Z]
After x[i+1] = "Z": i=1 s=M x=0xc000062180 [A Z Z Z Z]

Start: i=2 s=C x=0xc000062180 [A Z Z Z Z]
After x[i+1] = "M": i=2 s=C x=0xc000062180 [A Z Z M Z]
After Append: i=2 s=C x=0xc000062180 [A Z Z M Z Z]
After x[i+1] = "Z": i=2 s=C x=0xc000062180 [A Z Z Z Z Z]

Note how after the first append the address of x changes. Any x[i+] = ?no longer affects`.

huangapple
  • 本文由 发表于 2023年4月6日 03:06:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/75943183.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定