2012-04-12 17 views
5

Sto riscontrando problemi nel trasferire una variabile in una funzione anonima. C'è una soluzione?Vai: trasferimento var in funzione anonima

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) i = sempre 11

+0

Risolto anche in [le FAQ] (http://golang.org/doc/go_faq.html#closures_and_goroutines). – kostix

risposta

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

Pazzo come sembra, questo è qualcosa che vedrai nel codice Go. Deriva dal modo in cui funzionano le chiusure e dal modo in cui le variabili sono esaminate. La tua funzione anonima è una chiusura che cattura i. Specificamente, sta catturando una variabile chiamata i, non il valore corrente di i, e cattura qualunque cosa sia in ambito. Nel codice originale questa è la variabile loop, che è la stessa variabile per ogni iterazione del ciclo. Tutte le tue chiusure hanno catturato la stessa variabile. L'aggiunta di i := i dichiara una nuova variabile per ogni iterazione. Ora ogni chiusura catturerà questa nuova variabile e ad ogni iterazione sarà una variabile diversa.

In maggiore dettaglio, l'ambito della variabile di ciclo i è for. Ciò include il blocco del ciclo, ma poiché la dichiarazione della variabile di ciclo i è esterna al blocco, la dichiarazione di una nuova variabile con lo stesso nome all'interno del blocco è legale e crea una nuova variabile in quel punto nel blocco. La variabile di loop viene quindi ombreggiata. Spesso una variabile dichiarata come questa va in pila, ma in questo caso l'analisi di escape del compilatore vede che la tua chiusura si riferisce ancora a questa variabile di blocco quando esce dall'oscilloscopio alla fine del blocco, e quindi la variabile è posizionata sul mucchio. Ad ogni iterazione, il blocco viene reinserito e una nuova variabile i viene posizionata nell'heap.

+0

Sembra facile e quello di cui ho bisogno. – Vladislav

+0

Questo è in realtà un bel trucco. Dovrò ricordare quel trucco. –

6

penso che questo ti porterà ciò che si vuole:

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

Il trucco è quello di avere la funzione anonima restituisce un funzione anonima e ogni funzione creata includerà ciascuno dei valori di i.

4

Stai incontrando una stranezza di go for loop. La variabile i nel ciclo non è una nuova variabile per ogni iterazione. per questo tutte le chiusure si stanno chiudendo sulla stessa variabile il cui valore sta cambiando al di sotto di esse. Quando il codice viene eseguito dopo il ciclo, tutte le funzioni visualizzano il valore 11 per il punto in cui sono state chiuse.

La soluzione è passare la i in una funzione che restituisce un'altra funzione che chiude le funzioni arg. Ecco perché la soluzione di Adam Crosslands funziona.

Problemi correlati