functasks() { l := []int{1, 2, 3, 4, 5} var wg sync.WaitGroup for _, p := range l { wg.Add(1) gofunc() { defer wg.Done() fmt.Println(p) }() } wg.Wait() }
funcmain() { tasks() }
// 5 // 5 // 5 // 5 // 5
在 Go 中,for _, p := range l 的循环变量 p 是在整个循环中共享的单一变量。每次迭代时,p 的值会被更新,但它的地址不会改变。匿名函数 func() 中捕获的是 p 的引用,而不是 p 的值。所以当 Goroutine 被执行时,它访问的是同一个 p 的地址,而此时循环可能已经完成,p 的值已经是最后一次迭代的结果 5。
因此可以使用闭包将每个循环的值作为一个独立的副本,显示传递变量,执行的任务就不会捕获错误。
1 2 3 4 5 6 7 8 9 10 11 12
functasks() { l := []int{1, 2, 3, 4, 5} var wg sync.WaitGroup for _, p := range l { wg.Add(1) gofunc(t int) { defer wg.Done() fmt.Println(t) }(p) } wg.Wait() }