go for range slice 和 goroutine 方法调用,背后的逻辑

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循环变量在for-range循环中被重用了。

当 goroutine 有机会启动时,v 的值可能已被修改。所以打印结果将是 "three,three,three".

但是当我们将数据变量修改成另一个声明为:

data := []*field{{"one"},{"two"},{"three"}}

打印结果将是"one ,two,three"

我不明白为什么。指针有什么不同或任何不同的机制吗?

我从 this article 读到这篇文章。但海报并没有说明原因。或者这只是一个输出正确的事件。

在第一个循环中,vfield 项目的 value。因为 v 是可寻址的,所以它被自动引用为 print() 方法的指针接收器。所以 v.print() 正在使用 v 本身的地址,并且该地址的内容在循环的每次迭代中都会被覆盖。

当您更改声明以使用 *field 时,v 现在是指向 field 值的指针。在这种情况下调用 v.print() 时,您是在对 v 指向的值进行操作,该值存储在 data 中,而 v 的覆盖没有任何效果。