En Go, for range répète un bloc de code pour chaque valeur produite par une expression de range. Cette expression détermine si chaque itération produit une valeur ou deux.
range
range sur un slice produit l'indice et la valeur de chaque élément, dans l'ordre :
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(i, v)
}
// 0 10
// 1 20
// 2 30
range sur une map produit chaque clé et chaque valeur, mais l'ordre d'itération n'est pas garanti.
Go mélange délibérément l'ordre d'itération des maps, si bien qu'un même programme peut produire une sortie différente à chaque exécution.
hash := map[int]int{9: 10, 99: 20, 999: 30}
for k, v := range hash {
fmt.Println(k, v)
}
// 99 20
// 999 30
// 9 10
range sur une string produit l'indice d'octet et chaque rune (point de code Unicode).
Dans l'exemple suivant, 子 occupe trois octets, donc 猫 commence à l'indice d'octet 3, et non 1.
for i, r := range "子猫" {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 3 29483 猫
Si tu as besoin d'indices de rune à la place, convertis la string en une slice de rune :
for i, r := range []rune("子猫") {
fmt.Println(i, r, string(r))
}
// 0 23376 子
// 1 29483 猫
range peut itérer directement sur un entier, en produisant les valeurs de 0 jusqu'à cet entier exclu.
Les valeurs nulles ou négatives sont valides, mais ne produisent aucune itération.
for n := range 3 {
fmt.Println(n)
}
// 0
// 1
// 2
range accepte un itérateur de type iter.Seq[V] ou iter.Seq2[K, V].
Un itérateur est une fonction qui produit une séquence de valeurs, une à la fois.
range peut alors parcourir ces valeurs.
text := "The quick brown fox"
for word := range strings.FieldsSeq(text) {
fmt.Println(word)
}
// The
// quick
// brown
// fox
names := []string{"Alice", "Bob", "Vera"}
for i, v := range slices.All(names) {
fmt.Println(i, ":", v)
}
// 0 : Alice
// 1 : Bob
// 2 : Vera
Enfin, range peut recevoir les valeurs envoyées dans un canal jusqu'à ce que ce canal soit fermé ailleurs.
Les canaux sont traités en détail un peu plus loin dans le programme du parcours.
Go ne compile pas si une variable est déclarée mais jamais utilisée.
vals := []int{10, 20, 30}
for i, v := range vals {
fmt.Println(v)
}
// Go build failed: declared and not used: i
Si tu n'as besoin que de la valeur, affecte l'indice ou la clé à _ pour l'ignorer.
vals := []int{10, 20, 30}
for _, v := range vals {
fmt.Println(v)
}
// 10
// 20
// 30
Si tu n'as besoin que de l'indice, omets-le complètement :
vals := []int{10, 20, 30}
for i := range vals {
fmt.Println(i)
}
// 0
// 1
// 2
Si tu n'as besoin ni de l'indice ni de la valeur, tu peux omettre les deux :
vals := []int{10, 20, 30}
count := 0
for range vals {
count++
}
// count == 3