Les boucles en Rust
Rust propose trois façons de répéter du code : loop, while et for. Cette page présente loop, la plus simple et la plus directe des trois : elle répète à l’infini jusqu’à ce que vous lui disiez de s’arrêter.
Une boucle simple
Section intitulée « Une boucle simple »fn main() { let mut count = 0;
loop { count += 1; println!("{count}");
if count == 3 { break; } }}Sortie :
123Toute seule, loop ne s’arrête jamais : c’est break qui la termine. Sans ce if count == 3 { break; }, ce programme afficherait des nombres pour toujours.
Renvoyer une valeur depuis une boucle
Section intitulée « Renvoyer une valeur depuis une boucle »Voici une chose que loop sait faire, mais pas while ni for : vous pouvez placer une valeur après break, et elle devient le résultat de toute la boucle :
fn main() { let mut count = 0;
let result = loop { count += 1; if count == 10 { break count * 2; // on s'arrête et on renvoie une valeur } };
println!("{result}");}Sortie :
20C’est pratique pour des situations du type « réessaie jusqu’à ce que ça marche, puis donne-moi le résultat ». Vous croiserez ce schéma dans du vrai code plus souvent que vous ne le pensez.
Remarquez le point-virgule après l’accolade fermante } de la boucle. Toute la loop { ... } est le côté droit de let result = ...; : l’instruction let a donc besoin de son ; à la fin, comme dans let x = 5;.
Pourquoi loop plutôt que while true ?
Section intitulée « Pourquoi loop plutôt que while true ? »Si vous venez d’un autre langage, vous écririez peut-être une boucle infinie sous la forme while true { ... }. Cela fonctionne en Rust, mais le compilateur vous avertit :
warning: denote infinite loops with `loop { ... }` --> src/main.rs:5:5 |5 | while true { | ^^^^^^^^^^ help: use `loop`Le message conseille d’écrire les boucles infinies avec loop { ... }. Ce n’est pas qu’une question de style. Rust sait que le corps d’une loop s’exécute toujours, et que la seule façon d’en sortir est un break. Il ne suppose pas la même chose pour while true, car il ne regarde pas la valeur de la condition. Cela fait une vraie différence quand une variable reçoit sa valeur à l’intérieur de la boucle :
fn main() { let mut n = 1; let answer; // pas encore de valeur
loop { if n * n > 50 { answer = n * n; // on la définit juste avant de sortir break; } n += 1; }
println!("Le premier carré supérieur à 50 est {answer}");}Sortie :
Le premier carré supérieur à 50 est 64Avec loop, Rust voit que la seule façon d’atteindre println! passe par ce break : answer a donc toujours une valeur. Remplacez loop par while true et vous obtenez error[E0381]: used binding answer is possibly-uninitialized (la variable answer est utilisée alors qu’elle n’a peut-être pas été initialisée). Le compilateur pense que la boucle pourrait se terminer sans jamais exécuter le if.
En pratique, la version la plus propre de ce programme utilise break avec une valeur, comme vous l’avez vu plus haut : let answer = loop { ... break n * n; ... };. Dans les deux cas, la leçon est la même : quand vous voulez dire « pour toujours, jusqu’à ce que je fasse un break », écrivez loop.
Quand utiliser loop
Section intitulée « Quand utiliser loop »loop est le bon choix quand vous ne savez pas à l’avance combien de fois vous allez répéter : vous attendez qu’une condition devienne vraie, au lieu de compter sur une plage ou de parcourir une liste. Pour compter ou parcourir une collection, while et for (présentés ensuite) se lisent généralement mieux.
Exercices
Section intitulée « Exercices »1. Compte à rebours avant le décollage
Section intitulée « 1. Compte à rebours avant le décollage »Utilisez loop pour afficher un compte à rebours de 5 à 1, puis affichez Décollage !. Indice : commencez par let mut n = 5; et faites un break quand n atteint 0.
Voir la solution
fn main() { let mut n = 5;
loop { if n == 0 { break; } println!("{n}..."); n -= 1; }
println!("Décollage !");}Sortie :
5...4...3...2...1...Décollage !Le test vient en premier : quand n vaut 0, la boucle s’arrête avant d’afficher 0....
2. La première puissance de deux au-dessus de 1000
Section intitulée « 2. La première puissance de deux au-dessus de 1000 »Partez de 1 et doublez sans arrêt. Utilisez break avec une valeur pour obtenir le premier nombre supérieur à 1000, et comptez combien de doublements il a fallu. Indice : gardez un compteur mut en dehors de la boucle, et écrivez let power = loop { ... };.
Voir la solution
fn main() { let mut value = 1; let mut doublings = 0;
let power = loop { value *= 2; doublings += 1; if value > 1000 { break value; } };
println!("{power} après {doublings} doublements");}Sortie :
1024 après 10 doublementsbreak value; termine la boucle et transmet value à power. Le compteur vit en dehors de la boucle : il garde donc sa valeur une fois la boucle terminée.
Récapitulatif
Section intitulée « Récapitulatif »looprépète à l’infini jusqu’à ce qu’unbreakl’arrête : vérifiez toujours qu’il y en a un.break value;arrête la boucle et renvoievaluecomme résultat de toute l’expressionloop.- Écrivez
loop, paswhile true: Rust sait que le corps d’uneloops’exécute toujours, ce qui l’aide à vérifier vos variables. - Choisissez
loopquand vous répétez « jusqu’à ce que quelque chose se produise », pas quand vous comptez un nombre de tours connu.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Qu'est-ce qui empêche une loop de tourner à l'infini ?
2. À quoi sert break count * 2; dans une boucle ?
3. D'après cette page, quand loop est-il un meilleur choix que while ou for ?
4. Que se passe-t-il si vous écrivez while true { ... } en Rust ?
Score : 0 / 4
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Repetition with Loops — The Rust Book (en anglais) : la présentation officielle de
loop,whileetfor. - Returning Values from Loops — The Rust Book (en anglais) : une courte section sur
breakavec une valeur. - loop — Rust by Example (en anglais) : des exemples exécutables de
loop,breaketcontinue. - Returning from loops — Rust by Example (en anglais) : un autre petit exemple de boucle qui renvoie une valeur.
- Le mot-clé
loop— documentation de la bibliothèque standard (en anglais) : une référence compacte sur le fonctionnement conjoint deloopetbreak.