Ricerca…
Nozioni di base sulla chiusura
Una chiusura è una funzione presa insieme a un ambiente. La funzione è in genere una funzione anonima definita all'interno di un'altra funzione. L'ambiente è l'ambito lessicale della funzione di inclusione (l'idea di base di uno scope lessicale di una funzione sarebbe lo scopo che esiste tra le parentesi della funzione).
func g() {
i := 0
f := func() { // anonymous function
fmt.Println("f called")
}
}
All'interno del corpo di una funzione anonima (per esempio f
) definito all'interno di un'altra funzione (dire g
), le variabili presenti in ambiti sia f
e g
sono accessibili. Tuttavia, è lo scopo di g
che forma la parte dell'ambiente della chiusura (la parte della funzione è f
) e di conseguenza le modifiche apportate alle variabili nello scope di g
mantengono i loro valori (cioè l'ambiente persiste tra le chiamate a f
) .
Considera la seguente funzione:
func NaturalNumbers() func() int {
i := 0
f:= func() int { // f is the function part of closure
i++
return i
}
return f
}
In precedenza definizione, NaturalNumbers
ha una funzione interna f
che NaturalNumbers
rendimenti. All'interno di f
, si accede alla variabile i
definita nell'ambito di NaturalNumbers
.
Otteniamo una nuova funzione da NaturalNumbers
modo:
n := NaturalNumbers()
Ora n
è una chiusura. È una funzione (definita da f
) che ha anche un ambiente associato (ambito di NaturalNumbers
).
In caso di n
, la parte ambiente contiene solo una variabile: i
Poiché n
è una funzione, può essere chiamata:
fmt.Println(n()) // 1
fmt.Println(n()) // 2
fmt.Println(n()) // 3
Come evidente dall'output precedente, ogni volta che n
viene chiamato, incrementa i
. i
inizia a 0, e ogni chiamata di n
li esegue i++
.
Il valore di i
viene mantenuto tra le chiamate. Cioè, l'ambiente, essendo parte della chiusura, persiste.
Chiamando di nuovo NaturalNumbers
creerebbe e restituirà una nuova funzione. Ciò inizializzerebbe una nuova i
entro NaturalNumbers
. Il che significa che le forme funzionali di recente restituiti un'altra chiusura avere la stessa parte per la funzione (ancora f
), ma un ambiente nuovo di zecca (una nuova inizializzato i
).
o := NaturalNumbers()
fmt.Println(n()) // 4
fmt.Println(o()) // 1
fmt.Println(o()) // 2
fmt.Println(n()) // 5
Sia n
che o
sono chiusure contenenti la stessa parte di funzione (che dà loro lo stesso comportamento), ma ambienti diversi. Pertanto, l'uso di chiusure consente alle funzioni di accedere a un ambiente persistente che può essere utilizzato per conservare le informazioni tra le chiamate.
Un altro esempio:
func multiples(i int) func() int {
var x int = 0
return func() int {
x++
// paramenter to multiples (here it is i) also forms
// a part of the environment, and is retained
return x * i
}
}
two := multiples(2)
fmt.Println(two(), two(), two()) // 2 4 6
fortyTwo := multiples(42)
fmt.Println(fortyTwo(), fortyTwo(), fortyTwo()) // 42 84 126