If Let et While Let en Rust
Vous avez utilisé match pour traiter Option et Result. Pourtant, la plupart du temps, un seul motif vous intéresse vraiment et vous voulez ignorer tout le reste. Écrire un match complet avec une branche _ => {} qui ne fait rien fonctionne, mais c’est beaucoup de cérémonie pour pas grand-chose. if let est le raccourci.
Le problème d’un match complet ici
Section intitulée « Le problème d’un match complet ici »fn main() { let age: Option<i32> = Some(30);
match age { Some(value) => println!("L'âge est {value}"), _ => {}, // ce cas ne nous intéresse pas vraiment }}Ce _ => {} ne fait rien, à part satisfaire la règle de match selon laquelle « tous les cas doivent être traités ». Si vous voulez seulement agir sur Some, c’est plus de code que l’idée n’en mérite.
fn main() { let age: Option<i32> = Some(30);
if let Some(value) = age { println!("L'âge est {value}"); }}Sortie :
L'âge est 30Lisez-le ainsi : « si age correspond au motif Some(value), exécute ce bloc, avec value qui contient ce qu’il y avait à l’intérieur ». Si age vaut None, le bloc est simplement sauté : pas d’erreur, rien n’est affiché.
Ajouter un else
Section intitulée « Ajouter un else »if let peut avoir un else, exactement comme un if normal :
fn main() { let age: Option<i32> = None;
if let Some(value) = age { println!("L'âge est {value}"); } else { println!("Aucun âge indiqué"); }}if let avec Result
Section intitulée « if let avec Result »Cela fonctionne de la même façon avec Result, que vous avez rencontré sur la page Result :
fn main() { let input = "42";
if let Ok(number) = input.parse::<i32>() { println!("Converti : {number}"); } else { println!("Impossible de convertir ce texte"); }}Enchaîner avec else if let
Section intitulée « Enchaîner avec else if let »Comme if a else if, if let peut être suivi de else if let. Rust essaie chaque motif à tour de rôle et exécute le premier bloc qui correspond. C’est pratique quand vous avez plusieurs endroits où chercher une valeur, par ordre de préférence :
fn main() { let nickname: Option<&str> = None; let full_name: Option<&str> = Some("Ferris Crab");
if let Some(nick) = nickname { println!("Salut, {nick} !"); } else if let Some(name) = full_name { println!("Bonjour, {name}."); } else { println!("Bonjour, inconnu."); }}Sortie :
Bonjour, Ferris Crab.nickname vaut None, donc le premier bloc est sauté. full_name correspond à Some(name), donc ce bloc s’exécute, et le else final n’est jamais atteint. Vous pouvez aussi glisser une condition ordinaire, comme else if is_admin { ... }, n’importe où dans la chaîne.
Chaque variable n’existe que dans son propre bloc : nick n’est pas utilisable dans le deuxième bloc, et name n’est plus utilisable après la fin de la chaîne. Si vous avez besoin de la valeur déballée pour tout le reste de votre code, regardez let-else sur la page Le pattern matching.
while let
Section intitulée « while let »while let applique la même idée à une boucle : on continue tant qu’une valeur correspond à un motif. C’est particulièrement pratique pour vider une collection :
fn main() { let mut stack = vec![1, 2, 3];
while let Some(top) = stack.pop() { println!("{top}"); }}Sortie :
321.pop() renvoie Some(value) tant qu’il reste quelque chose, puis None une fois le vecteur vide. À ce moment-là, while let arrête la boucle tout seul. Pas besoin de vérifier la longueur à la main.
if let ou match : lequel choisir ?
Section intitulée « if let ou match : lequel choisir ? »Utilisez match quand vous devez vraiment traiter plusieurs cas de façons différentes. Préférez if let quand un seul motif vous intéresse et que tout le reste doit simplement être ignoré. Ce n’est pas un remplaçant de match : c’est juste une façon plus courte d’écrire le cas fréquent « seule une branche m’intéresse ».
Exercices
Section intitulée « Exercices »1. Additionner une pile
Section intitulée « 1. Additionner une pile »Partez de let mut numbers = vec![4, 8, 15]; et d’un total courant total à 0. Utilisez while let avec .pop() pour retirer les nombres de la fin un par un, ajoutez chacun à total, et affichez le nombre ainsi que le nouveau total. Indice : total doit être mut, et total += n lui ajoute une valeur.
Voir la solution
fn main() { let mut numbers = vec![4, 8, 15]; let mut total = 0;
while let Some(n) = numbers.pop() { total += n; println!("retiré {n}, le total vaut maintenant {total}"); }}Sortie :
retiré 15, le total vaut maintenant 15retiré 8, le total vaut maintenant 23retiré 4, le total vaut maintenant 27.pop() retire l’élément de la fin, c’est pourquoi 15 sort en premier.
2. Vérifier un âge écrit en texte
Section intitulée « 2. Vérifier un âge écrit en texte »Stockez let input = "17";. Si le texte se convertit en u32, affichez si cet âge correspond à un majeur (18 ans ou plus) ou à un mineur. S’il ne se convertit pas, affichez que ce n’est pas un nombre. Essayez aussi de remplacer input par "abc". Indice : placez un if / else normal à l’intérieur du bloc if let.
Voir la solution
fn main() { let input = "17";
if let Ok(age) = input.parse::<u32>() { if age >= 18 { println!("{age} ans : majeur"); } else { println!("{age} ans : mineur"); } } else { println!("'{input}' n'est pas un nombre"); }}Sortie :
17 ans : mineurAvec input = "abc", la conversion échoue, le else extérieur s’exécute et le programme affiche 'abc' n'est pas un nombre.
Récapitulatif
Section intitulée « Récapitulatif »if let Motif = valeur { ... }n’exécute le bloc que sivaleurcorrespond àMotif; tout le reste est ignoré sans bruit.- Ajoutez
elsepour traiter le cas où ça ne correspond pas, comme avec unifnormal, et enchaînez plusieurs motifs avecelse if let. while let Motif = valeur { ... }boucle tant que la valeur continue de correspondre ; pratique pour vider une collection avec.pop().- Utilisez
if let/while letquand un seul motif vous intéresse ; utilisezmatchquand vous devez traiter plusieurs cas distincts.
Petit quiz
Section intitulée « Petit quiz »Petit quiz
1. Que se passe-t-il quand if let Some(value) = age s'exécute et que age vaut None ?
2. Quand faut-il préférer match à if let ?
3. Dans while let Some(top) = stack.pop() { ... }, quand la boucle s'arrête-t-elle ?
Score : 0 / 3
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Concise Control Flow with if let and let…else — The Rust Book (en anglais) : la présentation officielle, qui couvre aussi let-else.
- if let — Rust by Example (en anglais) : des exemples exécutables avec
Optionet vos propres enums, et pourquoiif letvaut mieux quematchpour un seul motif. - while let — Rust by Example (en anglais) : une boucle
loop+matchréécrite en unwhile letplus court. - Motifs
if let— The Rust Reference (en anglais) : les règles exactes, y compris le lien entreif letetmatch.