考虑以下Golang代码(也在Go Playground上):
package main import "fmt" import "time" func main() { for _, s := range []string{"foo", "bar"} { x := s func() { fmt.Printf("s: %s\n", s) fmt.Printf("x: %s\n", x) }() } fmt.Println() for _, s := range []string{"foo", "bar"} { x := s go func() { fmt.Printf("s: %s\n", s) fmt.Printf("x: %s\n", x) }() } time.Sleep(time.Second) }
此代码产生以下输出:
s: foo x: foo s: bar x: bar s: bar x: foo s: bar x: bar
假设这不是一些奇怪的编译器错误,我很好奇为什么a)s的值在goroutine版本中的解释与常规func调用中的不同,并且b)为什么将其分配给循环内的局部变量起作用?两种情况。
Go中的闭包在词法范围内。这意味着闭包内从“外部”范围引用的任何变量都不是副本,而是实际上是引用。一for环竟重复使用相同的变量多次,所以你介绍的读/写之间的竞争条件s变量。
for
s
但是x正在分配一个新变量(带有:=)并进行复制s,这导致每次都是正确的结果。
x
:=
通常,最佳做法是传递所需的任何参数,以使您没有引用。例:
for _, s := range []string{"foo", "bar"} { x := s go func(s string) { fmt.Printf("s: %s\n", s) fmt.Printf("x: %s\n", x) }(s) }