Les Itérateurs en Go
Les itérateurs sont apparus tout récemment dans la version 1.23 de Go. Ils font suite à la généricité introduite en Go 1.18.
Nous pouvons illustrer les itérateurs avec un exemple simple qui génère les n premiers éléments de la fameuse suite de Fibonacci :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | |
0
1
1
2
3
5
8
13
...
2584
4181
La fonction Fibonacci retourne une fonction (l’itérateur) qui prend en argument une fonction (communément appelé yield) qui retourne un booléen.
Au passage, notez l’utilisation de l’instruction for range n de la ligne 10. Cette construction, introduite avec Go 1.22, remplace avantageusement une boucle for i := 0; i < n; i++ classique.
Lorsque l’itérateur est utilisé dans une boucle for range (ligne 20), Go crée automatiquement la fonction yield avec le corps de la boucle (ligne 21). À chaque itération, la fonction yield est appelée avec la valeur courante de la suite de Fibonacci. Si yield retourne false, l’itérateur s’arrête.
On obtient le même résultat en appelant explicitement l’itérateur avec une fonction anonyme :
Fibonacci(10)(func(i int) bool {
fmt.Println(i)
return true
})
mais l’utilisation dans une boucle for range est plus élégante.
Pour plus d’informations, vous pouvez consulter les articles suivants :
- ByteSizeGo : Iterators in Go 1.23
- Bitfield Consulting - Iterators in Go: the iter package and new stdlib APIs
Etudiez aussi le paquetage iter qui fournit des itérateurs pour les types de données courants.
Le paquetage iter permet de réécrire l’itérateur Fibonacci de la manière suivante :
func Fibonacci(n int) iter.Seq[int] {
return func(yield func(int) bool) {
f0, f1 := 0, 1
for range n {
if !yield(f0) {
return
}
f0, f1 = f1, f0+f1
}
}
}
À partir de Go 1.23, les paquetage slices et maps
de la bibliothèque standard ont été enrichis avec des fonctions utilisant des itérateurs.
Si on reprend l’exemple de la map avec les coordonnées géographiques, nous pouvons maintenant
utiliser un itérateur pour parcourir toutes les clés et les valeurs avec la fonction maps.All :
package main
import (
"fmt"
"maps"
)
type Coordinate struct {
Lat, Long float64
}
var m = map[string]Coordinate{
"HEIA-FR": {46.7926, 7.15993},
"Google": {37.42202, -122.08408},
}
func main() {
for k, v := range maps.All(m) {
fmt.Println(k, v)
}
}
Google {37.42202 -122.08408}
HEIA-FR {46.7926 7.15993}
Et si je ne veux que les clés, je peux utiliser la fonction maps.Keys :
func main() {
for k := range maps.Keys(m) {
fmt.Println(k)
}
}
HEIA-FR
Google