
Boucles (`for` - formes principales)
Explorez la polyvalence de l'unique boucle `for` en Go. Apprenez ses différentes formes : la clause à trois composants, la boucle conditionnelle (while) et la boucle infinie.
L'unique boucle de Go : Introduction à `for`
Après avoir appris à prendre des décisions avec `if`/`else`, l'étape suivante pour construire des algorithmes plus complexes est de pouvoir répéter des blocs de code. C'est le rôle des boucles. Contrairement à de nombreux autres langages qui proposent plusieurs mots-clés pour les boucles (comme `while`, `do-while`, `for`), Go adopte une approche minimaliste et ne fournit qu'une seule structure de boucle : l'instruction `for`.
Cette unique instruction `for` est cependant extrêmement flexible et permet de couvrir tous les cas d'utilisation typiques des boucles. Sa conception vise la simplicité et la cohérence, en évitant la redondance de plusieurs constructions pour des concepts similaires.
Dans ce sous-chapitre, nous allons explorer les trois formes principales de la boucle `for` en Go : la forme classique avec une clause à trois composants (initialisation, condition, post-instruction), la forme qui agit comme une boucle `while` (basée uniquement sur une condition), et la forme de boucle infinie. Une quatrième forme, `for range`, spécifiquement conçue pour itérer sur les collections, sera abordée plus en détail dans les chapitres suivants.
La boucle `for` classique : Initialisation, condition, post-instruction
La forme la plus complète et souvent la plus familière pour les développeurs venant d'autres langages (comme C, Java, C#) est celle qui contient trois composants séparés par des points-virgules : une instruction d'initialisation, une expression de condition et une instruction post-itération.
La syntaxe générale est la suivante :
for initialisation; condition; post {
// Corps de la boucle : exécuté tant que la condition est true
}Voici le déroulement :- Initialisation : Cette instruction est exécutée une seule fois, au tout début, avant la première évaluation de la condition. Elle est souvent utilisée pour déclarer et initialiser une variable de compteur (par exemple, `i := 0`). Les variables déclarées ici ont une portée limitée au bloc de la boucle `for`.
- Condition : Cette expression booléenne est évaluée avant chaque itération (y compris la première). Si elle est `true`, le corps de la boucle est exécuté. Si elle est `false`, la boucle se termine et l'exécution continue après le bloc `for`.
- Post-instruction : Cette instruction est exécutée à la fin de chaque itération, après l'exécution du corps de la boucle et avant la prochaine évaluation de la condition. Elle est typiquement utilisée pour incrémenter ou décrémenter le compteur (par exemple, `i++`).
Voyons un exemple classique qui affiche les nombres de 0 à 4 :
package main
import "fmt"
func main() {
fmt.Println("Début de la boucle classique")
for i := 0; i < 5; i++ {
fmt.Printf("Itération numéro : %d\n", i)
}
fmt.Println("Fin de la boucle classique")
// fmt.Println(i) // Erreur ici : 'i' n'est pas défini en dehors de la boucle
}Dans cet exemple, `i := 0` est l'initialisation, `i < 5` est la condition, et `i++` est la post-instruction. La variable `i` est créée et initialisée à 0. La condition `0 < 5` est vraie, le corps s'exécute (affiche 0). `i++` est exécuté (i devient 1). La condition `1 < 5` est vraie, le corps s'exécute (affiche 1), et ainsi de suite jusqu'à ce que `i` devienne 5. La condition `5 < 5` est fausse, la boucle se termine.Simuler `while` avec `for` : La boucle conditionnelle
Go permet d'omettre l'instruction d'initialisation et la post-instruction de la clause `for`, ne laissant que la condition. Lorsque seule la condition est présente, la boucle `for` se comporte exactement comme une boucle `while` dans d'autres langages.
La syntaxe est simple :
for condition {
// Corps de la boucle : exécuté tant que la condition est true
}Ici, la boucle continue de s'exécuter tant que l'expression `condition` est évaluée à `true`. Il est de la responsabilité du code à l'intérieur du corps de la boucle (ou ailleurs) de modifier éventuellement les variables impliquées dans la condition pour qu'elle devienne fausse à un moment donné, afin d'éviter une boucle infinie (à moins que ce ne soit l'intention).Voici un exemple qui simule une boucle `while`. Nous initialisons une variable avant la boucle et la modifions à l'intérieur :
package main
import "fmt"
func main() {
somme := 1
fmt.Println("Début de la boucle 'while'")
for somme < 100 {
fmt.Printf("Somme actuelle : %d\n", somme)
somme += somme // Double la somme à chaque itération
}
fmt.Printf("Fin de la boucle 'while', somme finale : %d\n", somme)
}Dans ce cas, la boucle s'exécute tant que `somme` est strictement inférieur à 100. A chaque itération, la valeur de `somme` est doublée. La boucle s'arrêtera lorsque `somme` atteindra ou dépassera 100 (1, 2, 4, 8, 16, 32, 64, puis 128 - la boucle s'arrête avant l'itération qui utiliserait 128).Itération infinie : La boucle `for` sans condition
Il est également possible d'omettre les trois composants de la clause `for`. Dans ce cas, on obtient une boucle infinie, qui s'exécutera indéfiniment à moins qu'elle ne soit explicitement interrompue depuis l'intérieur.
La syntaxe est la plus simple possible :
for {
// Corps de la boucle : s'exécute indéfiniment
// ... nécessite une sortie explicite (break, return, panic) ...
}Les boucles infinies sont utiles dans certains scénarios, par exemple :- Dans les serveurs qui doivent écouter en permanence les connexions entrantes.
- Pour implémenter des boucles d'événements ou des agents qui s'exécutent en arrière-plan.
- Lorsque la condition de sortie est complexe et mieux gérée par une instruction `if` suivie d'un `break` à l'intérieur du corps de la boucle.
Pour sortir d'une boucle infinie (ou de toute boucle `for` d'ailleurs), on utilise généralement l'instruction `break`. Voici un exemple où une boucle infinie est utilisée pour lire des entrées jusqu'à ce qu'une condition spécifique soit remplie :
package main
import (
"fmt"
"time"
)
func main() {
compteur := 0
fmt.Println("Début de la boucle infinie (avec break)")
for {
fmt.Printf("Itération infinie : %d\n", compteur)
compteur++
time.Sleep(500 * time.Millisecond) // Pause pour ne pas surcharger
if compteur >= 5 {
fmt.Println("Condition de sortie atteinte. Break!")
break // Sort de la boucle for
}
}
fmt.Println("Fin de la boucle infinie")
}Cette boucle s'exécutera, en incrémentant `compteur`, jusqu'à ce que `compteur` atteigne 5. A ce moment, l'instruction `break` est exécutée, provoquant la sortie immédiate de la boucle `for`.Contrôler le flux interne : `break` et `continue`
En plus de la condition de la boucle elle-même, Go fournit deux instructions pour contrôler plus finement le déroulement des itérations depuis l'intérieur du corps de la boucle : `break` et `continue`.
Nous avons déjà vu `break`. Il provoque la sortie immédiate de la boucle `for` (ou `switch` ou `select`) la plus interne dans laquelle il se trouve. L'exécution reprend à la première instruction suivant la boucle terminée. C'est le moyen standard de terminer une boucle prématurément, que ce soit une boucle infinie ou une boucle conditionnelle/classique dont on veut sortir avant que la condition ne devienne fausse.
L'instruction `continue`, quant à elle, ne termine pas la boucle entière. Elle arrête l'itération courante et passe directement au début de l'itération suivante. Dans une boucle `for` classique (avec les trois composants), l'instruction `post` est exécutée après un `continue`, avant que la condition ne soit réévaluée pour l'itération suivante. Dans les autres formes de `for`, l'évaluation de la condition (si elle existe) se fait immédiatement après le `continue`.
`continue` est utile lorsque vous voulez ignorer le reste du traitement pour l'itération actuelle et passer à la suivante. Par exemple, pour traiter uniquement les nombres impairs :
package main
import "fmt"
func main() {
fmt.Println("Utilisation de continue pour sauter les pairs")
for i := 0; i < 10; i++ {
if i%2 == 0 { // Si i est pair
continue // Saute le reste de l'itération
}
// Ce code n'est exécuté que si i est impair
fmt.Printf("Traitement du nombre impair : %d\n", i)
}
fmt.Println("Fin de la boucle avec continue")
}Ce code affichera le traitement uniquement pour les nombres 1, 3, 5, 7 et 9.En maîtrisant ces différentes formes de la boucle `for` ainsi que les instructions `break` et `continue`, vous disposez des outils nécessaires pour implémenter toutes sortes de logiques répétitives dans vos programmes Go.