Aller au contenu

La boucle for en Rust

for parcourt un intervalle ou une collection, un élément à la fois. Des trois types de boucles de Rust, c’est celle que vous utiliserez le plus souvent.

fn main() {
for i in 1..=5 {
println!("{i}");
}
}

Sortie :

1
2
3
4
5
▶ Essayez par vous-même

1..=5 est un intervalle (range) qui inclut ses deux bornes (de 1 à 5). Si vous retirez le =, 1..5 s’arrête un cran plus tôt et vous donne 1 à 4. Ce décalage d’une unité est facile à rater : vérifiez bien lequel des deux vous vouliez.

C’est là que for brille vraiment : parcourir un tableau ou un vecteur sans gérer d’indice vous-même.

fn main() {
let fruits = ["pomme", "banane", "cerise"];
for fruit in fruits {
println!("{fruit}");
}
}

Sortie :

pomme
banane
cerise
▶ Essayez par vous-même

Comparez avec une boucle while qui compte à la main et accède aux éléments par indice (fruits[i]) : c’est plus court, et il n’y a aucun indice à rater. Vous en apprendrez plus sur les tableaux et les vecteurs aux pages Tableaux et Vecteurs.

Si vous avez besoin à la fois de la position et de la valeur, utilisez .enumerate() :

fn main() {
let fruits = ["pomme", "banane", "cerise"];
for (index, fruit) in fruits.iter().enumerate() {
println!("{index}: {fruit}");
}
}

Sortie :

0: pomme
1: banane
2: cerise
▶ Essayez par vous-même

La partie (index, fruit) est un pattern de tuple : à chaque tour, vous recevez une paire, et la boucle la découpe pour vous en deux variables.

Et si vous voulez compter à rebours depuis 3, ou ne prendre qu’un nombre sur deux ? Le premier réflexe est d’écrire un intervalle à l’envers, comme 3..=1. Ça compile, mais la boucle ne s’exécute jamais. Un intervalle ne compte que vers le haut : si son début est plus grand que sa fin, il est tout simplement vide.

À la place, partez d’un intervalle normal et changez la façon de le parcourir :

  • .rev() parcourt l’intervalle à l’envers.
  • .step_by(n) prend une valeur toutes les n, en commençant par la première.
fn main() {
for i in (1..=3).rev() {
println!("{i}...");
}
println!("Partez !");
for even in (0..=10).step_by(2) {
print!("{even} ");
}
println!();
for i in 3..=1 {
println!("ceci ne s'affiche jamais : {i}");
}
}

Sortie :

3...
2...
1...
Partez !
0 2 4 6 8 10
▶ Essayez par vous-même

Remarquez les parenthèses : (1..=3).rev(). Sans elles, Rust lirait 1..=3.rev() comme « de 1 jusqu’à 3.rev() », ce qui n’est pas ce que vous voulez. Vous pouvez aussi combiner les deux : (0..=10).rev().step_by(5) donne 10, 5, 0.

Vous pourriez écrire une boucle qui compte avec while, mais for avec un intervalle élimine toute une catégorie d’erreurs : pas de compteur à mettre à jour (et donc à oublier), et aucun risque de dépasser d’un cran la fin d’un tableau. Les développeurs Rust utilisent for par défaut et ne passent à while que lorsqu’il n’y a pas d’intervalle ou de collection naturelle à parcourir.

Affichez la table de 7, de 7 x 1 = 7 jusqu’à 7 x 10 = 70. Indice : une seule boucle for sur 1..=10 suffit. Vous pouvez faire la multiplication directement dans println!.

Voir la solution
fn main() {
for i in 1..=10 {
println!("7 x {i} = {}", 7 * i);
}
}

Sortie :

7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70
▶ Essayez par vous-même

Les noms de variables comme {i} peuvent aller directement entre les accolades. Un calcul comme 7 * i, non : on utilise donc des accolades vides {} et on met la valeur après la virgule.

Additionnez tous les nombres impairs de 1 à 99 et affichez le total. Indice : (1..100).step_by(2) vous donne 1, 3, 5, … 99. Gardez un total mut en dehors de la boucle.

Voir la solution
fn main() {
let mut total = 0;
for n in (1..100).step_by(2) {
total += n;
}
println!("La somme des nombres impairs de 1 à 99 vaut {total}");
}

Sortie :

La somme des nombres impairs de 1 à 99 vaut 2500
▶ Essayez par vous-même

Une autre solution consiste à parcourir 1..100 et à n’ajouter n que si n % 2 == 1. Les deux fonctionnent. step_by saute simplement les nombres pairs au lieu de tester chacun d’eux.

  • for element in intervalle_ou_collection { ... } est la boucle de tous les jours en Rust.
  • 1..=5 inclut les deux bornes ; 1..5 s’arrête juste avant 5.
  • Parcourez directement les tableaux et les vecteurs pour obtenir chaque valeur sans gérer d’indice.
  • Utilisez .enumerate() quand vous avez besoin de l’indice en plus de la valeur.
  • Un intervalle à l’envers comme 3..=1 est vide. Utilisez (1..=3).rev() pour compter à rebours, et .step_by(n) pour avancer par pas.

Petit quiz

1. Quelle est la différence entre 1..=5 et 1..5 dans une boucle for ?

2. Comment obtenir à la fois l'indice et la valeur en parcourant une collection ?

3. Pourquoi préfère-t-on généralement for à while pour parcourir une collection ?

4. Que fait for i in 5..=1 { ... } ?

Score : 0 / 4