Ce face pattern matching (tipare)
Un tipar (pattern) seamănă cu felul în care construiești valoarea, dar este folosit invers: o desface. let (x, y) = (3, 4); desface un tuplu, let Punct { x, y } = p; desface o structură, Some(n) scoate valoarea din Option. Tiparele apar în let, match, if let, while let, for și în parametrii funcțiilor și ai closure-urilor.
Elemente utile: _ ignoră o valoare, .. ignoră restul câmpurilor sau al elementelor, | dă alternative, a..=b potrivește un interval, nume @ tipar leagă valoarea de un nume și verifică în același timp tiparul, iar [prim, rest @ ..] desface un slice.
ref într-un tipar înseamnă „împrumută, nu muta”: let Elev { ref nume, .. } = elev; dă o referință la nume, iar elev rămâne întreg. Când potrivești o referință (match &elev), Rust împrumută automat câmpurile, deci ref nu mai este necesar; în ediția 2024, a scrie ref în acest caz este chiar eroare.
Exemple
Exemplul 1: Desfacerea structurilor și a tuplurilor
Parametrul funcției distanta este el însuși un tipar care desface tuplul. În let, .. ignoră câmpul judet.
struct Oras {
nume: String,
judet: String,
coordonate: (f64, f64),
}
fn distanta((x1, y1): (f64, f64), (x2, y2): (f64, f64)) -> f64 {
((x2 - x1).powi(2) + (y2 - y1).powi(2)).sqrt()
}
fn main() {
let iasi = Oras { nume: "Iași".into(), judet: "IS".into(), coordonate: (47.16, 27.59) };
let Oras { nume, coordonate: (lat, lon), .. } = &iasi;
println!("{nume} ({}): lat {lat}, lon {lon}", iasi.judet);
println!("Distanța în grade până la (46.77, 23.60): {:.2}", distanta(iasi.coordonate, (46.77, 23.60)));
}
Rezultat
Iași (IS): lat 47.16, lon 27.59
Distanța în grade până la (46.77, 23.60): 4.01
Exemplul 2: Slice-uri, intervale și @
[prima, .., ultima] potrivește orice slice cu cel puțin două elemente. n @ 90..=100 verifică intervalul și păstrează valoarea în n.
fn rezumat(punctaje: &[u32]) -> String {
match punctaje {
[] => "niciun punctaj".to_string(),
[unic] => format!("un singur punctaj: {unic}"),
[prima, .., ultima] => format!("{} punctaje, de la {prima} la {ultima}", punctaje.len()),
}
}
fn nivel(p: u32) -> String {
match p {
n @ 90..=100 => format!("{n}: excelent"),
n @ 50..90 => format!("{n}: trecut"),
n => format!("{n}: picat"),
}
}
fn main() {
println!("{}", rezumat(&[]));
println!("{}", rezumat(&[72]));
println!("{}", rezumat(&[45, 80, 95, 60]));
for p in [95, 72, 30] {
println!("{}", nivel(p));
}
}
Rezultat
niciun punctaj
un singur punctaj: 72
4 punctaje, de la 45 la 60
95: excelent
72: trecut
30: picat
Exemplul 3: ref: împrumut în loc de mutare
Fără ref, let Elev { nume, .. } = elev; ar muta textul din elev, iar elev nu ar mai putea fi afișat. Cu ref, nume este doar o referință (&String).
#[derive(Debug)]
struct Elev {
nume: String,
clasa: u8,
}
fn main() {
let elev = Elev { nume: String::from("Ioana"), clasa: 10 };
let Elev { ref nume, clasa } = elev;
println!("{nume} este în clasa a {clasa}-a");
println!("Elevul este încă întreg: {elev:?}");
}
Rezultat
Ioana este în clasa a 10-a
Elevul este încă întreg: Elev { nume: "Ioana", clasa: 10 }
Greșeli frecvente
- Desfaci o structură care conține un
Stringfără&saurefși apoi folosești structura: textul a fost mutat (E0382). Potrivește&valoaresau foloseșteref. - Scrii
refcând potrivești deja o referință (match &x { Some(ref s) => ... }). În ediția 2024 este eroare; scrie doarSome(s), iarsva fi referință. - Folosești în
letun tipar care poate eșua:let Some(x) = optiune;nu se compilează (E0005), pentru că ar putea fiNone. Foloseștelet ... else,if letsaumatch.
Comenzi înrudite
match: Compară o valoare cu o listă de tipare și execută ramura primului care se potrivește. Compilatorul verifică dacă toate cazurile sunt tratate.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.while let: Repetă un bloc cât timp o valoare se potrivește cu un tipar, de exemplu cât timp pop() mai returnează Some.struct: Definește un tip nou care grupează mai multe valori cu nume (câmpuri), de exemplu un elev cu nume, clasă și medie.tuple (tupluri): Grupează un număr fix de valori, de tipuri diferite, într-o singură valoare. Elementele se citesc cu .0, .1 sau prin desfacere.