除非复制变量,否则go例程中的闭包具有不正确的作用域

时间:2014-06-13 00:58:25

标签: go

我在goroutines中运行的函数中看到的值不正确。除非复制到新变量中,否则它们似乎不会从调用它们的范围捕获值。

http://play.golang.org/p/YZYi-IVuYm

VS

http://play.golang.org/p/z88G99XSi6

3 个答案:

答案 0 :(得分:7)

您需要在本地竞赛中重新分配变量,以便闭包可以捕获值:

http://play.golang.org/p/-NO4S4qCZf

package main

import "fmt"
import "time"

func main() {
    l := []int{1, 2, 3}
    for idx, item := range l {
        theIdx, theItem := idx, item
        go func() {
            fmt.Println(theIdx, theItem)
        }()
    }
    time.Sleep(time.Second)
}

或者将值传递给goroutine并将参数添加到函数

http://play.golang.org/p/5gNToDWSQR

package main

import "fmt"
import "time"

func main() {
    l := []int{1, 2, 3}
    for idx, item := range l {
        go func(idx, item int) {
            fmt.Println(idx, item)
        }(idx, item)
    }
    time.Sleep(time.Second)
}

答案 1 :(得分:6)

这是预期的,并记录在Go" Common Mistakes"页。您可以与设计决策争论,但这是已知的效果。

建议的方法是将值作为参数传递。

答案 2 :(得分:0)

在执行第一个goroutine时,idxitem已经被下一个值覆盖。由于例程是在同一范围内执行的,因此您将获得新值。

事后看来,这确实是有道理的。