Ce face match
match ia o valoare și o compară, de sus în jos, cu tiparele din ramuri. Se execută doar prima ramură care se potrivește. Tiparele pot fi constante (3), intervale (1..=4), alternative ('a' | 'e'), variante de enum (Some(x)), tupluri, structuri și _ (orice).
Cel mai important: match trebuie să fie exhaustiv. Dacă există o valoare posibilă pe care nu o tratează nicio ramură, programul nu se compilează (eroarea E0004). Când adaugi o variantă nouă într-un enum, compilatorul îți arată toate locurile unde trebuie tratată.
match este o expresie, deci poate da o valoare, iar toate ramurile trebuie să aibă același tip. O gardă (x if x > 100 =>) adaugă o condiție în plus unei ramuri.
Exemple
Exemplul 1: Numere, intervale și alternative
Fiecare zi a săptămânii este tratată; 6 | 7 potrivește două valori, iar _ prinde orice număr invalid.
fn tip_zi(zi: u8) -> &'static str {
match zi {
1..=5 => "zi lucrătoare",
6 | 7 => "weekend",
_ => "zi invalidă",
}
}
fn main() {
for zi in [1, 5, 6, 7, 9] {
println!("{zi}: {}", tip_zi(zi));
}
}
Rezultat
1: zi lucrătoare
5: zi lucrătoare
6: weekend
7: weekend
9: zi invalidă
Exemplul 2: match pe un enum, cu gardă
Fiecare variantă a lui Plata are ramura ei. Garda if suma > 5000 separă plățile mari cu cardul de restul. Valorile din variante (suma, iban) sunt extrase direct în tipar.
enum Plata {
Numerar(u32),
Card { suma: u32, banca: String },
Transfer { suma: u32, iban: String },
}
fn descrie(p: &Plata) -> String {
match p {
Plata::Numerar(suma) => format!("{suma} lei numerar"),
Plata::Card { suma, .. } if *suma > 5000 => format!("{suma} lei cu cardul (cere confirmare)"),
Plata::Card { suma, banca } => format!("{suma} lei cu cardul {banca}"),
Plata::Transfer { suma, iban } => format!("{suma} lei prin transfer din {iban}"),
}
}
fn main() {
let plati = [
Plata::Numerar(50),
Plata::Card { suma: 120, banca: "BT".to_string() },
Plata::Card { suma: 7200, banca: "BCR".to_string() },
Plata::Transfer { suma: 900, iban: "RO49AAAA1B31007593840000".to_string() },
];
for p in &plati {
println!("{}", descrie(p));
}
}
Rezultat
50 lei numerar
120 lei cu cardul BT
7200 lei cu cardul (cere confirmare)
900 lei prin transfer din RO49AAAA1B31007593840000
Exemplul 3: Un caz uitat nu trece de compilare
Varianta Galben nu are ramură. Compilatorul refuză programul și arată exact ce lipsește.
enum Semafor {
Rosu,
Galben,
Verde,
}
fn actiune(s: Semafor) -> &'static str {
match s {
Semafor::Rosu => "oprește",
Semafor::Verde => "treci",
}
}
fn main() {
println!("{}", actiune(Semafor::Verde));
println!("{}", actiune(Semafor::Rosu));
println!("{}", actiune(Semafor::Galben));
}
Mesajul compilatorului (programul nu se compilează)
error[E0004]: non-exhaustive patterns: `Semafor::Galben` not covered
--> main.rs:8:11
|
8 | match s {
| ^ pattern `Semafor::Galben` not covered
|
note: `Semafor` defined here
--> main.rs:1:6
|
1 | enum Semafor {
| ^^^^^^^
2 | Rosu,
3 | Galben,
| ------ not covered
= note: the matched value is of type `Semafor`
help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown
|
10 ~ Semafor::Verde => "treci",
11 ~ Semafor::Galben => todo!(),
|
error: aborting due to 1 previous error
For more information about this error, try `rustc --explain E0004`.
Greșeli frecvente
- Pui ramura
_prima: ea potrivește orice, deci ramurile de după ea nu se mai execută niciodată (compilatorul avertizeazăunreachable pattern). - Folosești
_ =>într-unmatchpe propriul tăuenum. Programul se compilează, dar pierzi avantajul: când adaugi o variantă nouă, compilatorul nu te mai anunță unde trebuie tratată. - Crezi că un nume simplu dintr-un tipar compară cu o variabilă:
match x { limita => ... }nu compară cu variabilalimita, ci creează o variabilă nouă care potrivește orice. Folosește o gardă:v if v == limita =>.
Comenzi înrudite
pattern matching (tipare): Tiparele descriu forma unei valori și scot din ea părțile de care ai nevoie: în let, match, if let, for și parametrii funcțiilor.if let și let else: if let execută un bloc doar dacă o valoare se potrivește cu un tipar; let else desface valoarea sau iese imediat din funcție.enum: Definește un tip care poate fi exact una dintre mai multe variante; fiecare variantă poate avea propriile date.matches!: Returnează true dacă o valoare se potrivește cu un tipar (ca într-o ramură de match) și false altfel.if și else: Execută un bloc de cod doar dacă o condiție bool este adevărată. În Rust, if este o expresie: poate da o valoare.