5

我无法将变量转换为匿名函数。有解决办法吗?

import  "github.com/lxn/walk"

***

var openAction [12]*walk.Action
for i := 0; i < 12; i++ {

    openBmp, err := walk.NewBitmapFromFile(_films[i][0])
    if err != nil {
        log.Printf("Open bitmap for buildBody() :%v\n", err)
    }
    openAction[i] = walk.NewAction()
    openAction[i].SetImage(openBmp)
    openAction[i].SetText(_films[i][2])
    openAction[i].Triggered().Attach( func(){
        exec(i)
    })
    mw.ToolBar().Actions().Add(openAction[i])
}

exec(i)其中我总是 = 11

4

3 回答 3

10
for i := 0; i < 12; i++ {
    i := i
    ...

Crazy as it looks, this is something you will see in Go code. It results from the way closures work and the way variables are scoped. Your anonymous function is a closure that captures i. Specifically, it is capturing a variable called i, not the current value of i, and it captures whatever i is in scope. In your original code this is the loop variable, which is the same variable for each iteration of the loop. All of your closures captured the same variable. The addition of i := i declares a new variable on each iteration. Now each closure will capture this new variable, and on each iteration it will be a different variable.

In a little more detail, the scope of the loop variable i is the for statement. This includes the loop block, but since the declaration of the loop variable i is outside of the block, declaring a new variable with the same name inside the block is legal and creates a new variable at that point in the block. The loop variable is then shadowed. Often a variable declared like this goes on the stack, but in this case compiler escape analysis sees that your closure is still referring to this block variable when it goes out of scope at the end of the block, and so the variable is placed on the heap. On each iteration, the block is reentered and a new variable i is placed on the heap.

于 2012-04-12T03:41:42.260 回答
6

我认为这会让你得到你想要的:

openAction[i].Triggered().Attach(func(x int) func() {
    return func() { exec(x) }
}(i))

诀窍是让您的匿名函数返回一个匿名函数,并且每个创建的函数都将包含i的每个值。

于 2012-04-12T02:31:23.980 回答
4

您遇到了 go 的 for 循环的怪癖。循环中的 i 变量不是每次迭代的新变量。因此,您所有的闭包都关闭了同一个变量,该变量的值在它们下面发生了变化。当您的代码在循环之后运行时,所有函数都会看到它们关闭的 i 的值 11。

解决方案是将 i 传递给一个函数,然后返回另一个关闭函数 arg 的函数。这就是 Adam Crosslands 解决方案有效的原因。

于 2012-04-12T02:41:51.090 回答