前往:将var转换为匿名函数

问题描述:

我无法将变量转换为匿名函数。有解决方案吗?前往:将var转换为匿名函数

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

+0

在[常见问题解答](http://golang.org/doc/go_faq.html#closures_and_goroutines)中回答也是如此。 – kostix 2012-04-12 08:22:18

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

疯狂,因为它看起来,这是你会看到的转到代码。它来自封闭方式的工作方式以及方法变量的范围。你的匿名函数是捕获i的闭包。具体来说,它捕获一个名为i的变量,而不是i的当前值,它捕获我在范围内的任何东西。在您的原始代码中,这是循环变量,对于循环的每次迭代而言都是相同的变量。您所有的关闭都会捕获相同的变量。 i := i的添加在每次迭代中声明一个新变量。现在每个闭包都将捕获这个新变量,并且在每次迭代时它将是一个不同的变量。

稍微详细一点,循环变量i的范围是for语句。这包括循环块,但由于循环变量i的声明位于块的外部,因此在块内声明一个具有相同名称的新变量是合法的,并在该块的该点处创建一个新变量。循环变量然后被阴影化。通常这样一个变量会出现在堆栈中,但在这种情况下,编译器转义分析会发现,当它在块结束时超出范围时,您的闭包仍会引用此块变量,因此变量将放置在堆。在每次迭代中,该块将被重新输入,并将一个新变量i放在堆上。

+0

看起来很简单,我需要什么。 – Vladislav 2012-04-12 04:50:44

+0

这实际上是一个整洁的黑客。我将不得不记住那个伎俩。 – 2012-04-12 14:32:41

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

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

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

你遇到了一个循环的怪癖。循环中的i变量不是每次迭代的新变量。因为你的所有关闭都在关闭同一个变量,而这个变量的值在它们下面变化。当你的代码在循环后运行时,所有的函数都会看到它们关闭的i的值11。

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