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
我很好奇为什么?
s 的值在 goroutine 中的解释与在常规 func 调用中的结果不同
为什么在这两种情况下都将其分配给循环内的局部变量
回答
Go 中的闭包依赖词法作用域。这意味着任何在闭包内对外部变量的引用,都不是一个拷贝。for 循环实际上会在多次循环中重用同一个变量,所以你需要处理 s 变量在读写时竞态条件。
但 x 会被分配一个新的变量(使用 :=)并拷贝 s,来保证每次的结果都是正确的。
通常,最佳实践是通过参数传入需要的变量,例如:
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)
}
问题
考虑下面的代码:
这段代码产生以下输出:
我很好奇为什么?
回答
Go 中的闭包依赖词法作用域。这意味着任何在闭包内对外部变量的引用,都不是一个拷贝。
for
循环实际上会在多次循环中重用同一个变量,所以你需要处理s
变量在读写时竞态条件。但
x
会被分配一个新的变量(使用:=
)并拷贝s
,来保证每次的结果都是正确的。通常,最佳实践是通过参数传入需要的变量,例如: