A: Параметры оцениваются до вызова функции. После того, как они вычисляются, параметры вызова передаются по значению к функции и вызываемая функция начинается выполнение, так что:
Первого go v.print()
является синтаксическим сахаром для go (*field).print(&v)
и
второго go v.print()
является синтаксическим сахаром для go (*field).print(v)
.
Если первый for
цикл заканчивается перед запуском горутов, &v
- это то же самое для вызовов, и эти три вызова одинаковы. См. Код 2, добавив time.Sleep(100)
после go v.print()
в первый цикл. или с go func(v field) { v.print() }(v)
по адресу The Go Playground (Code 3 with sync.WaitGroup
).
Кроме того, у вас есть данные гонки здесь (см. B).
А для второго go (*field).print(v)
здесь v
является указателем и три goroutines параметра вычисляется перед вызовом print
и имеют три разных адреса.
1- Попробуйте это на The Go Playground:
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 {
fmt.Println(&v)
go (*field).print(&v) //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 {
fmt.Println(v)
go (*field).print(v) //go v.print()
}
time.Sleep(time.Second)
}
выход:
use values:
&{one}
&{two}
&{three}
three
three
three
use pointers:
&{one}
&{two}
&{three}
two
one
three
2- Попробуйте это на The Go Playground:
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 {
fmt.Println(&v)
go v.print() //go (*field).print(&v) //
time.Sleep(100)
}
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 {
fmt.Println(v)
go v.print() //go (*field).print(v) //
}
time.Sleep(time.Second)
}
выход:
use values:
&{one}
one
&{two}
two
&{three}
three
use pointers:
&{one}
&{two}
&{three}
one
two
three
B: У вас есть гонки данных, попробуйте go build -race
your code, а затем запустить созданный файл, WARNING: DATA RACE
:
выход:
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)