Pointers for range循环中指针和值片之间的差异

Pointers for range循环中指针和值片之间的差异,pointers,for-loop,go,goroutine,Pointers,For Loop,Go,Goroutine,请检查此代码段: package main import ( "fmt" "time" ) type field struct { name string } func (p *field) print() { fmt.Println(p.name) } func main() { fmt.Println("use values:") // use values in range loop and go rountines

请检查此代码段:

package main

import (  
    "fmt"
    "time"
)

type field struct {  
    name string
}

func (p *field) print() {  
    fmt.Println(p.name)
}

func main() {
    fmt.Println("use values:")

    // use values in range loop and go rountines
    values := []field{{"one"},{"two"},{"three"}}
    for _, v := range values {
        go v.print()
    }

    time.Sleep(time.Second)

    fmt.Println()
    fmt.Println("use pointers:")

    // use pointers in range loop and go rountines
    poniters := []*field{{"one"},{"two"},{"three"}}
    for _, v := range poniters {
        go v.print()
    }

    time.Sleep(time.Second)
}
链接此处:

上面的代码将检查for循环中指针和值之间的差异,同时也使用go语句。代码:

values := []field{{"one"},{"two"},{"three"}}
for _, v := range values {
    go v.print()
}
我们知道控制台将打印three,因为for循环在goroutines开始执行之前运行到它的末尾,goroutines将v写入片的最后一个元素。但是指针呢

poniters := []*field{{"one"},{"two"},{"three"}}
for _, v := range poniters {
    go v.print()
}
它似乎在打印一二三,为什么


谢谢。

A:在调用函数之前会对参数进行评估。求值后,调用的参数按值传递给函数,被调用函数开始执行,因此:

第一个
go v.print()
第二个
go v.print()

如果
的第一个
循环在goroutines开始之前完成,
&v
对于调用是相同的,并且这三个调用都是相同的。参见代码2,将
time.Sleep(100)
添加到第一个循环的
go v.print()
之后。或者使用
go func(v字段){v.print()}(v)
on.
此外,这里还有数据竞赛(参见B)

对于第二个
go(*字段),print(v)
这里
v
是指针,在调用
print
之前计算了三个goroutines参数,它们有三个不同的地址

1-试试这个:

输出:

use values:
&{one}
&{two}
&{three}
three
three
three

use pointers:
&{one}
&{two}
&{three}
two
one
three
use values:
&{one}
one
&{two}
two
&{three}
three

use pointers:
&{one}
&{two}
&{three}
one
two
three
use values:
==================
WARNING: DATA RACE
Read at 0x00c042030210 by goroutine 6:
  runtime.convT2E()
      Go/src/runtime/iface.go:155 +0x0
  main.(*field).print()
      .../m.go:14 +0x6c

Previous write at 0x00c042030210 by main goroutine:
  main.main()
      .../m.go:22 +0x1c3

Goroutine 6 (running) created at:
  main.main()
      .../m.go:23 +0x204
==================
two
three
three

use pointers:
one
two
three
Found 1 data race(s)

2-试试这个:

输出:

use values:
&{one}
&{two}
&{three}
three
three
three

use pointers:
&{one}
&{two}
&{three}
two
one
three
use values:
&{one}
one
&{two}
two
&{three}
three

use pointers:
&{one}
&{two}
&{three}
one
two
three
use values:
==================
WARNING: DATA RACE
Read at 0x00c042030210 by goroutine 6:
  runtime.convT2E()
      Go/src/runtime/iface.go:155 +0x0
  main.(*field).print()
      .../m.go:14 +0x6c

Previous write at 0x00c042030210 by main goroutine:
  main.main()
      .../m.go:22 +0x1c3

Goroutine 6 (running) created at:
  main.main()
      .../m.go:23 +0x204
==================
two
three
three

use pointers:
one
two
three
Found 1 data race(s)

B:您有数据竞争,请尝试
go build-race
,然后运行生成的文件,
警告:数据竞争

输出:

use values:
&{one}
&{two}
&{three}
three
three
three

use pointers:
&{one}
&{two}
&{three}
two
one
three
use values:
&{one}
one
&{two}
two
&{three}
three

use pointers:
&{one}
&{two}
&{three}
one
two
three
use values:
==================
WARNING: DATA RACE
Read at 0x00c042030210 by goroutine 6:
  runtime.convT2E()
      Go/src/runtime/iface.go:155 +0x0
  main.(*field).print()
      .../m.go:14 +0x6c

Previous write at 0x00c042030210 by main goroutine:
  main.main()
      .../m.go:22 +0x1c3

Goroutine 6 (running) created at:
  main.main()
      .../m.go:23 +0x204
==================
two
three
three

use pointers:
one
two
three
Found 1 data race(s)