Ce face closures (funcții anonime)
O funcție anonimă (func(...) { ... }, fără nume) poate folosi variabilele din funcția în care a fost scrisă. Dacă face asta, se numește closure: ea păstrează legătura cu acele variabile (nu o copie), deci le vede valorile curente și le poate modifica, chiar și după ce funcția care le-a creat s-a terminat.
Closure-urile se folosesc pentru generatoare și contoare cu stare, pentru funcții trimise ca argument (slices.SortFunc, http.HandleFunc), pentru defer și pentru goroutine. Din Go 1.22, variabilele unei bucle for sunt noi la fiecare iterație, deci closure-urile create în buclă nu mai împart aceeași variabilă.
Exemple
Exemplul 1: Contor cu stare proprie
Fiecare apel al lui contor() creează un n nou; cele două contoare sunt independente.
package main
import "fmt"
func contor() func() int {
n := 0
return func() int {
n++
return n
}
}
func main() {
bilete := contor()
fmt.Println(bilete(), bilete(), bilete())
altul := contor()
fmt.Println(altul(), bilete())
}
Rezultat
1 2 3
1 4
Exemplul 2: Closure trimis la sortare
Funcția anonimă folosește ordine din exterior.
package main
import (
"fmt"
"slices"
)
func main() {
ordine := map[string]int{"urgent": 0, "normal": 1, "scăzut": 2}
sarcini := []string{"normal", "scăzut", "urgent", "normal"}
slices.SortFunc(sarcini, func(a, b string) int {
return ordine[a] - ordine[b]
})
fmt.Println(sarcini)
}
Rezultat
[urgent normal normal scăzut]
Exemplul 3: Closures create într-o buclă (Go 1.22+)
Fiecare iterație are propriul oras, deci fiecare funcție îl ține minte pe al ei.
package main
import "fmt"
func main() {
var saluturi []func()
for _, oras := range []string{"Iași", "Cluj", "Arad"} {
saluturi = append(saluturi, func() { fmt.Println("Salut din", oras) })
}
for _, s := range saluturi {
s()
}
}
Rezultat
Salut din Iași
Salut din Cluj
Salut din Arad
Greșeli frecvente
- Crezând că closure-ul copiază variabila: o împarte cu funcția exterioară; modificările se văd în ambele părți.
- Modificarea aceleiași variabile din mai multe goroutine prin closure-uri, fără
sync.Mutex: rezultat imprevizibil (data race). - Cod scris pentru Go vechi cu
v := vîn buclă: din Go 1.22 nu mai este necesar.
Comenzi înrudite
func: Declară o funcție: parametri cu tip după nume, unul sau mai multe rezultate, metode și funcții anonime.defer: Amână un apel de funcție până la ieșirea din funcția curentă; folosit pentru închideri și curățenie.go și goroutine: Cuvântul go pornește o funcție într-o goroutine: un fir de execuție ușor, care rulează în paralel cu restul programului.for range peste funcții (iteratori): Din Go 1.23, for range parcurge funcții iterator: funcții care trimit pe rând valorile prin yield.