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 读到这篇文章。但海报并没有说明原因。或者这只是一个输出正确的事件。
在第一个循环中,v
是 field
项目的 value。因为 v
是可寻址的,所以它被自动引用为 print()
方法的指针接收器。所以 v.print()
正在使用 v
本身的地址,并且该地址的内容在循环的每次迭代中都会被覆盖。
当您更改声明以使用 *field
时,v
现在是指向 field
值的指针。在这种情况下调用 v.print()
时,您是在对 v
指向的值进行操作,该值存储在 data
中,而 v
的覆盖没有任何效果。
代码如下:
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 读到这篇文章。但海报并没有说明原因。或者这只是一个输出正确的事件。
在第一个循环中,v
是 field
项目的 value。因为 v
是可寻址的,所以它被自动引用为 print()
方法的指针接收器。所以 v.print()
正在使用 v
本身的地址,并且该地址的内容在循环的每次迭代中都会被覆盖。
当您更改声明以使用 *field
时,v
现在是指向 field
值的指针。在这种情况下调用 v.print()
时,您是在对 v
指向的值进行操作,该值存储在 data
中,而 v
的覆盖没有任何效果。