2012-04-12 17 views
5

Tengo problemas para transferir una variable a una función anónima. ¿Hay una solución?Ir: transferir var a la función anónima

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) donde siempre = 11

+0

Respondido en [las Preguntas frecuentes] (http://golang.org/doc/go_faq.html#closures_and_goroutines) también. – kostix

Respuesta

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

Tan loco como parece, esto es algo que verá en el código Go. Resulta de la forma en que funcionan los cierres y de la forma en que se definen las variables. Su función anónima es un cierre que captura i. Específicamente, está capturando una variable llamada i, no el valor actual de i, y captura lo que sea que esté en el alcance. En su código original, esta es la variable de bucle, que es la misma variable para cada iteración del bucle. Todos tus cierres capturaron la misma variable. La adición de i := i declara una nueva variable en cada iteración. Ahora cada cierre capturará esta nueva variable, y en cada iteración será una variable diferente.

Con un poco más de detalle, el alcance de la variable de bucle i es la instrucción for. Esto incluye el bloque de bucle, pero como la declaración de la variable de bucle i está fuera del bloque, declarar una nueva variable con el mismo nombre dentro del bloque es legal y crea una nueva variable en ese punto del bloque. La variable de bucle se sombrea. A menudo, una variable declarada así va a la pila, pero en este caso el análisis de escape del compilador ve que su cierre sigue refiriéndose a esta variable de bloque cuando sale del alcance al final del bloque, por lo que la variable se coloca en el montón. En cada iteración, el bloque vuelve a entrar y una nueva variable i se coloca en el montón.

+0

Mira fácil y lo que necesito. – Vladislav

+0

Eso es realmente un truco limpio. Voy a tener que recordar ese truco. –

6

creo que esto va a conseguir lo que quiere:

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

El truco es tener su función anónima devolver una función anónima, y ​​cada función creada incluirá cada uno de los valores de i.

4

Te encuentras con un capricho de go's for loops. La variable i en el ciclo no es una nueva variable para cada iteración. debido a esto, todos sus cierres se cierran sobre la misma variable cuyo valor está cambiando debajo de ellos. Cuando su código se ejecuta después del ciclo, todas las funciones ven el valor 11 para el i que cerraron.

La solución es pasar el i a una función que luego devuelve otra función que cierra las funciones arg. Esta es la razón por la cual la solución de Adam Crosslands funciona.