英文:
go for range slice and goroutine method invocation,the logic behind
问题
代码如下:
package main
import (
"fmt"
"time"
)
type field struct {
name string
}
func (p *field) print() {
fmt.Println(p.name)
}
func main() {
data := []field{{"one"}, {"two"}, {"three"}}
for _, v := range data {
go v.print()
}
time.Sleep(3 * time.Second)
}
我知道这段代码是错误的,因为在 for-range 循环中重用了 for 循环变量。
当 goroutine 有机会启动时,v
的值可能已经被修改。所以打印的结果将是 "three,three,three"
。
但是当我们将 data 变量修改为另一种声明方式时:
data := []*field{{"one"}, {"two"}, {"three"}}
打印的结果将是 "one, two, three"
。
我不明白其中的原因。指针是否有任何区别,或者是否存在其他不同的机制?
我从这篇文章中读到了这个问题。但是作者没有解释原因。或者这只是一个输出正确的偶然事件。
<details>
<summary>英文:</summary>
The code is like the following:
package main
import (
"fmt"
"time"
)
type field struct {
name string
}
func (p *field) print() {
fmt.Println(p.name)
}
func main() {
data := []field{{"one"},{"two"},{"three"}}
for _,v := range data {
go v.print()
}
time.Sleep(3 * time.Second)
}
I know that the code is wrong,because the for loop variable is reused in the for-range loop.
When the goroutine has got the chance to launch,the value of `v` might has been modified. so the print result will be `"three,three,three"`.
But when we modify the data variable into another declaration as:
data := []*field{{"one"},{"two"},{"three"}}
the print result will be `"one ,two,three"`.
I didn't get the point of why. Does the pointer make any difference or any different mechanism is on this?
I read this from [this article][1]. But the poster didn't not tell why. Or it's just a incident the output is right.
[1]: http://devs.cloudimmunity.com/gotchas-and-common-mistakes-in-go-golang/index.html#range_val_update
</details>
# 答案1
**得分**: 1
在第一个循环中,`v` 是 `field` 项的 *值*。因为 `v` 是可寻址的,它会自动作为指针接收器被引用到 `print()` 方法中。所以 `v.print()` 使用的是 `v` 本身的地址,而该地址的内容在每次循环迭代时被覆盖。
当你将声明更改为使用 `*field` 时,`v` 现在是指向 `field` 值的指针。在这种情况下调用 `v.print()`,你操作的是 `v` 指向的值,该值存储在 `data` 中,而对 `v` 的覆盖没有影响。
<details>
<summary>英文:</summary>
In the first loop, `v` is the *value* of a `field` item. Because `v` is addressable, it is automatically referenced as the pointer receiver for the `print()` method. So `v.print()` is using the address of `v` itself, and the contents of that address is overwritten each iteration of the loop.
When you change the declaration to use a `*field`, `v` is now a pointer to a `field` value. When you call `v.print()` in this case, you are operating on the value that `v` points to, which is stored in `data`, and the overwriting of `v` has no effect.
</details>
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论