Ce face for range peste funcții (iteratori)
Un iterator este o funcție care primește o altă funcție, numită de obicei yield, și o apelează pentru fiecare valoare pe care vrea să o dea. Dacă yield returnează false (bucla a făcut break sau return), iteratorul trebuie să se oprească imediat. Pachetul iter denumește aceste forme: iter.Seq[V] pentru o valoare și iter.Seq2[K, V] pentru perechi.
Din Go 1.23, astfel de funcții se pot parcurge direct cu for v := range seq. Biblioteca standard oferă multe iteratoare: maps.Keys, maps.All, slices.Values, slices.Backward, strings.SplitSeq, iar slices.Collect și slices.Sorted le transformă înapoi în slice-uri.
Avantajul: valorile se produc doar când sunt cerute, deci poți parcurge șiruri foarte lungi sau infinite fără să le ții în memorie.
Exemple
Exemplul 1: Un iterator propriu
pare dă valorile pe rând; break face ca yield să returneze false.
package main
import (
"fmt"
"iter"
)
func pare(limita int) iter.Seq[int] {
return func(yield func(int) bool) {
for i := 0; i <= limita; i += 2 {
if !yield(i) {
return
}
}
}
}
func main() {
for n := range pare(10) {
fmt.Print(n, " ")
}
fmt.Println()
for n := range pare(1000000) {
if n > 6 {
break
}
fmt.Print(n, " ")
}
fmt.Println()
}
Rezultat
0 2 4 6 8 10
0 2 4 6
Exemplul 2: Iterator cu perechi (iter.Seq2)
package main
import (
"fmt"
"iter"
)
type Elev struct {
Nume string
Nota int
}
func promovati(elevi []Elev) iter.Seq2[int, Elev] {
return func(yield func(int, Elev) bool) {
for i, e := range elevi {
if e.Nota >= 5 && !yield(i, e) {
return
}
}
}
}
func main() {
clasa := []Elev{{"Ana", 9}, {"Mihai", 4}, {"Ioana", 7}}
for i, e := range promovati(clasa) {
fmt.Printf("%d: %s (%d)\n", i, e.Nume, e.Nota)
}
}
Rezultat
0: Ana (9)
2: Ioana (7)
Exemplul 3: Iteratori din biblioteca standard
package main
import (
"fmt"
"maps"
"slices"
"strings"
)
func main() {
stoc := map[string]int{"mere": 12, "pere": 0, "prune": 5}
for _, fruct := range slices.Sorted(maps.Keys(stoc)) {
fmt.Println(fruct, stoc[fruct])
}
for i, v := range slices.Backward([]string{"a", "b", "c"}) {
fmt.Print(i, v, " ")
}
fmt.Println()
for parte := range strings.SplitSeq("Iași,Cluj,Arad", ",") {
fmt.Println("oraș:", parte)
}
}
Rezultat
mere 12
pere 0
prune 5
2c 1b 0a
oraș: Iași
oraș: Cluj
oraș: Arad
Greșeli frecvente
- Ignorarea rezultatului lui
yield: dacă bucla facebreakși iteratorul mai apeleazăyield, programul se oprește cupanic: runtime error: range function continued iteration after function for loop body returned false. - Folosirea iteratorilor în Go mai vechi de 1.23: nu compilează.
Comenzi înrudite
range: Parcurge într-un for elementele unui slice, array, map, text, canal, număr sau iterator.for: Singura buclă din Go: forma clasică, forma „while”, bucla infinită și parcurgerea cu range.closures (funcții anonime): Funcții anonime care „țin minte” variabilele din jurul lor și le pot citi și modifica după ce funcția exterioară s-a terminat.generics (parametri de tip): Funcții și tipuri care lucrează cu mai multe tipuri, scrise o singură dată cu parametri de tip [T constrângere].