Menu

Boucle for en Golang : les quatre formes avec exemples

Go n'a qu'un seul mot-clé de boucle, for, et il couvre tout : la boucle compteur à trois clauses, la boucle while à condition seule, la boucle infinie, et range sur des slices, maps, chaînes, channels, entiers et fonctions. Plus break et continue avec étiquette, et le changement des variables de boucle de Go 1.22.

Cette page contient des éditeurs exécutables - modifiez, exécutez et voyez la sortie instantanément.

Go a exactement un mot-clé de boucle : for. Il a quatre formes, et à elles quatre elles couvrent toutes les boucles que vous écririez avec for, while, do while ou foreach dans d'autres langages.

Pas de parenthèses autour de l'en-tête de la boucle, et les accolades sont toujours obligatoires.

La boucle à trois clauses

for init; condition; post {
	// body
}
  1. init s'exécute une fois avant la boucle. C'est généralement une déclaration courte de variable comme i := 0, et cette variable n'existe qu'à l'intérieur de la boucle.
  2. condition est vérifiée avant chaque itération. Quand elle est fausse, la boucle se termine.
  3. Le corps s'exécute.
  4. post s'exécute après chaque itération, typiquement i++.

En Go, i++ est une instruction, pas une expression, donc post ne peut pas contenir i++, j--. Utilisez plutôt une affectation parallèle : i, j = i+1, j-1.

Les trois clauses sont facultatives. for ; i < 10; {} est légal, et gofmt le réécrit en for i < 10 {}, qui est la forme suivante.

La boucle à condition seule (le while de Go)

Avec seulement une condition, for se comporte comme while dans d'autres langages :

Il n'y a pas de do while séparé. La page sur la boucle while montre comment obtenir un comportement « exécuter au moins une fois ».

Boucles infinies

for sans rien derrière boucle indéfiniment. On en sort avec break, return, os.Exit ou un panic :

for {
	line, err := reader.ReadString('\n')
	if err != nil {
		break
	}
	process(line)
}

C'est la forme standard pour les serveurs, les workers et les boucles de lecture d'entrée. Un for {} au corps vide consomme un cœur de CPU ; dans du vrai code, le corps bloque sur quelque chose (une lecture, une réception sur un channel, un select).

Les boucles range

range parcourt une collection et fournit une ou deux valeurs par itération. Ce qu'elles sont dépend de ce que vous parcourez :

Parcours dePremière valeurDeuxième valeur
slice ou tableauindiceélément (une copie)
chaîneindice d'octetrune (caractère Unicode)
mapclévaleur
channelélément(aucune)
entier n (Go 1.22)0 à n moins 1(aucune)
fonction itérateur (Go 1.23)ce que la fonction fournitce que la fonction fournit

Trois détails visibles dans la sortie :

  • La variable valeur est une copie. v *= 2 dans la boucle ne modifierait pas la slice ; pour modifier les éléments, indexez la slice avec nums[i], comme le fait la troisième boucle.
  • L'indice d'une chaîne est une position en octets. é occupe deux octets, donc l'indice saute de 1 à 3.
  • L'ordre des maps est aléatoire exprès. Go le rend aléatoire pour que le code ne puisse pas en dépendre. slices.Sorted(maps.Keys(m)) (Go 1.23) donne les clés dans l'ordre.

range est traité en entier, y compris les channels, les fonctions itérateurs et les règles de copie, sur la page range.

break et continue

break termine la boucle la plus interne. continue passe à l'itération suivante (en exécutant d'abord post, dans une boucle à trois clauses) :

break et continue avec étiquette

Un simple break ne quitte que la boucle la plus interne. Pour sortir d'une boucle extérieure depuis une boucle imbriquée, étiquetez la boucle extérieure :

Une étiquette est un identifiant suivi de deux-points, placé juste avant le for. Go signale une étiquette inutilisée comme erreur de compilation, comme une variable inutilisée.

break dans switch et select

Dans un for, un break placé dans un cas de switch ou de select quitte le switch ou le select, pas la boucle :

for {
	switch cmd := next(); cmd {
	case "quit":
		break // only exits the switch; the loop keeps running
	}
}

Utilisez un break étiqueté, ou return, pour quitter la boucle depuis un switch ou un select.

Les variables de boucle depuis Go 1.22

Go 1.22 a changé la portée des variables de boucle : chaque itération reçoit désormais une nouvelle copie de i et v. Avant, une seule variable était réutilisée pour toute la boucle, ce qui cassait les closures et les goroutines qui la capturaient :

Avec Go 1.22 et plus, ce programme affiche 0 1 2 et [aa bb cc]. Avec l'ancienne sémantique, le même programme écrit avec for i := 0; i < 3; i++ (le range sur un entier n'existait pas avant 1.22) affichait 3 3 3, et les goroutines entraient en concurrence sur les i et name partagés. L'ancien contournement, i := i en haut du corps de la boucle, n'est plus nécessaire.

Le comportement est choisi par module via la ligne go du go.mod, pas par la version du compilateur. Un module qui indique encore go 1.21 garde l'ancienne sémantique même compilé avec Go 1.24.

Erreurs courantes

Modifier la copie. for _, v := range items { v.Count++ } modifie une copie. Utilisez items[i].Count++, ou parcourez une slice de pointeurs.

Ajouter des éléments pendant le parcours. range évalue la slice une seule fois, au début. Les éléments ajoutés dans la boucle ne sont pas visités, donc la boucle se termine quand même, mais elle ne verra pas les nouveaux éléments.

Supprimer d'une slice par indice dans une boucle qui avance. Retirer l'élément i décale le reste vers la gauche, donc l'élément suivant est sauté. Construisez une nouvelle slice, bouclez à l'envers, ou utilisez slices.DeleteFunc.

Le décalage d'un avec <=. for i := 0; i <= len(s); i++ lit s[len(s)] au dernier passage et provoque un panic index out of range. Utilisez <, ou mieux, range.

Un calcul lourd dans la condition. La condition s'exécute à chaque itération. for i := 0; i < expensiveCount(); i++ appelle la fonction à chaque fois ; calculez-la une fois avant la boucle.

Utiliser un flottant comme compteur. for x := 0.0; x != 1.0; x += 0.1 ne se termine jamais, parce que 0.1 n'a pas de représentation binaire exacte. Comptez avec un entier et calculez le flottant à partir de celui-ci.

Questions fréquentes

Comment écrire une boucle for en Go ?

La forme classique a trois parties séparées par des points-virgules, sans parenthèses :

for i := 0; i < 5; i++ {
	fmt.Println(i)
}

Depuis Go 1.22, vous pouvez aussi écrire for i := range 5, qui compte de 0 à 4. Pour parcourir une slice, utilisez for i, v := range items.

Go a-t-il une boucle while ?

Pas de mot-clé while, mais for avec seulement une condition est une boucle while : for n > 0 { n /= 2 }. for { ... } sans condition est une boucle infinie dont vous sortez avec break ou return.

Comment parcourir une map en Go ?

for key, value := range m { ... }. L'ordre d'itération n'est pas spécifié, et le runtime le rend aléatoire, donc il peut varier d'une boucle à l'autre. Ne comptez jamais dessus. Pour un ordre stable, collectez les clés, triez-les avec slices.Sort et parcourez les clés triées.

Comment sortir d'une boucle imbriquée en Go ?

Placez une étiquette avant la boucle extérieure et nommez-la dans le break : outer: for ... { for ... { if found { break outer } } }. Un simple break ne quitte que le for, switch ou select le plus interne. continue outer passe de même à l'itération suivante de la boucle étiquetée.

Qu'est-ce qui a changé pour les variables de boucle en Go 1.22 ?

Avant Go 1.22, une boucle for avait une seule variable partagée par toutes les itérations, donc les closures et les goroutines lancées dans la boucle voyaient souvent toutes la valeur finale. Depuis Go 1.22, chaque itération reçoit sa propre copie, donc capturer i ou v dans une closure fonctionne comme prévu. Le nouveau comportement s'applique quand le go.mod du module indique go 1.22 ou plus.

Coddy programming languages illustration

Apprendre à coder avec Coddy

COMMENCER