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