Aller au contenu

Match en Rust

match compare une valeur à une liste de motifs (patterns) et exécute le code de celui qui correspond. Si vous avez déjà utilisé une instruction switch, voyez-le comme une version bien plus puissante. Et si vous n’en avez jamais utilisé, c’est quand même l’un des outils les plus utiles à apprendre tôt.

fn main() {
let day = 3;
match day {
1 => println!("Lundi"),
2 => println!("Mardi"),
3 => println!("Mercredi"),
4 => println!("Jeudi"),
5 => println!("Vendredi"),
_ => println!("Week-end"),
}
}

Sortie :

Mercredi
▶ Essayez par vous-même

Le _ est un motif « attrape-tout » : il correspond à tout ce qui n’est pas listé au-dessus. match exige que chaque valeur possible soit traitée, c’est pourquoi _ est souvent là pour couvrir « tout le reste ».

Vous pouvez regrouper plusieurs valeurs dans une seule branche avec | :

fn main() {
let day = 6;
match day {
1 | 2 | 3 | 4 | 5 => println!("Jour de semaine"),
6 | 7 => println!("Week-end"),
_ => println!("Jour invalide"),
}
}
▶ Essayez par vous-même

Pour les nombres, vous pouvez faire correspondre toute une plage avec ..= :

fn main() {
let score = 85;
match score {
90..=100 => println!("A"),
75..=89 => println!("B"),
60..=74 => println!("C"),
_ => println!("F"),
}
}
▶ Essayez par vous-même

Comme if, match peut produire une valeur :

fn main() {
let day = 6;
let kind = match day {
1 | 2 | 3 | 4 | 5 => "jour de semaine",
6 | 7 => "week-end",
_ => "inconnu",
};
println!("{kind}");
}
▶ Essayez par vous-même

match ne sert pas qu’aux nombres. Il fonctionne aussi avec les string slices (&str) et les caractères, et les plages de caractères comme 'a'..='z' marchent exactement comme les plages de nombres :

fn main() {
let command = "stop";
match command {
"start" => println!("Démarrage..."),
"stop" | "quit" => println!("Arrêt."),
_ => println!("Commande inconnue : {command}"),
}
let letter = 'k';
let kind = match letter {
'a' | 'e' | 'i' | 'o' | 'u' => "voyelle",
'a'..='z' => "consonne",
'0'..='9' => "chiffre",
_ => "autre chose",
};
println!("'{letter}' : {kind}");
let name = String::from("Ferris");
match name.as_str() {
"Ferris" => println!("Salut, le crabe !"),
_ => println!("Salut, {name} !"),
}
}

Sortie :

Arrêt.
'k' : consonne
Salut, le crabe !
▶ Essayez par vous-même

Deux choses méritent votre attention :

  • L’ordre compte. 'a' fait aussi partie de 'a'..='z', mais la branche des voyelles vient en premier : les voyelles n’atteignent donc jamais la branche des consonnes. Rust choisit toujours la première branche qui correspond.
  • Une String a besoin de .as_str(). Un texte écrit entre guillemets, comme "Ferris", est un &str. Si vous faites un match directement sur une String, Rust s’arrête avec error[E0308]: mismatched types ... expected String, found &str (les types ne correspondent pas : il attendait une String et a trouvé un &str). Appeler .as_str() vous donne une vue &str de la String, que les motifs peuvent comparer. (Voir la page Les chaînes de caractères pour la différence entre les deux.)

La correspondance est sensible à la casse : "Stop" ne correspond pas à "stop". Si le texte vient d’un utilisateur, une astuce courante consiste à faire le match sur input.to_lowercase().as_str().

Les deux conviennent pour un simple test vrai/faux, mais match prend l’avantage dès que vous avez plus de deux ou trois possibilités : il se lit mieux qu’une longue chaîne de else if, et le compilateur vérifie que vous avez couvert tous les cas. if/else reste le bon outil pour une seule condition oui/non.

Stockez un numéro de mois month (2). Utilisez match comme expression pour calculer combien de jours il compte (sans tenir compte des années bissextiles), puis affichez Le mois 2 a 28 jours. Indice : les mois 1, 3, 5, 7, 8, 10 et 12 ont 31 jours ; regroupez-les dans une seule branche avec |.

Voir la solution
fn main() {
let month = 2;
let days = match month {
1 | 3 | 5 | 7 | 8 | 10 | 12 => 31,
4 | 6 | 9 | 11 => 30,
2 => 28,
_ => 0, // ce n'est pas un vrai mois
};
println!("Le mois {month} a {days} jours");
}

Sortie :

Le mois 2 a 28 jours
▶ Essayez par vous-même

Les serveurs web répondent avec un nombre. Transformez un code en une courte explication : 200 donne "OK", 404 donne "Not Found", tout autre code entre 400 et 499 donne "Erreur client", entre 500 et 599 "Erreur serveur", et tout le reste "Inconnu". Essayez avec 503. Indice : placez la branche exacte 404 au-dessus de la plage 400..=499, sinon elle ne sera jamais atteinte.

Voir la solution
fn main() {
let code = 503;
let meaning = match code {
200 => "OK",
404 => "Not Found", // doit venir avant la plage 400..=499
400..=499 => "Erreur client",
500..=599 => "Erreur serveur",
_ => "Inconnu",
};
println!("{code} : {meaning}");
}

Sortie :

503 : Erreur serveur
▶ Essayez par vous-même

"OK" et "Not Found" restent en anglais : ce sont les libellés officiels que renvoient les serveurs HTTP.

  • match compare une valeur à des motifs et exécute la branche qui correspond.
  • Chaque valeur possible doit être traitée : utilisez _ comme attrape-tout.
  • Regroupez des valeurs avec |, ou faites correspondre une plage avec ..=.
  • Vous pouvez aussi faire un match sur du texte &str et des valeurs char ; utilisez .as_str() pour une String.
  • Comme if, match peut servir d’expression pour produire une valeur.

Petit quiz

1. À quoi sert le motif _ dans une expression match ?

2. Que se passe-t-il si un match ne traite pas toutes les valeurs possibles et n'a pas de branche _ ?

3. Comment faire correspondre plusieurs valeurs dans une même branche, comme 1, 2 ou 3 ?

Score : 0 / 3