Ce face if let și let else
if let este un match scurt, cu un singur caz interesant: if let Some(pret) = cauta("pâine") { ... } execută blocul doar dacă rezultatul este Some, iar în bloc pret este valoarea scoasă. Ramura else este opțională.
let ... else (Rust 1.65) face invers: dacă tiparul se potrivește, variabilele rămân disponibile după instrucțiune; dacă nu, se execută blocul else, care trebuie să iasă (return, break, continue sau panică). Este ideal pentru verificări la începutul unei funcții, fără să adâncești codul în acolade.
În ediția 2024 (Rust 1.88), condițiile se pot înlănțui cu &&: if let Some(x) = a && let Ok(n) = x.parse::<u32>() && n > 10 { ... }. Fiecare legătură este disponibilă în condițiile de după ea și în bloc.
Exemple
Exemplul 1: if let cu Option
cauta returnează Option<u32>. Pentru produsele găsite se afișează prețul, pentru celelalte se execută else.
fn cauta(produs: &str) -> Option<u32> {
match produs {
"pâine" => Some(5),
"lapte" => Some(9),
_ => None,
}
}
fn main() {
for produs in ["pâine", "cafea", "lapte"] {
if let Some(pret) = cauta(produs) {
println!("{produs}: {pret} lei");
} else {
println!("{produs}: nu există în stoc");
}
}
}
Rezultat
pâine: 5 lei
cafea: nu există în stoc
lapte: 9 lei
Exemplul 2: let else pentru verificări la început
Fiecare rând este desfăcut în nume și notă. Dacă lipsește : sau nota nu este număr, let else sare la rândul următor cu continue. După verificări, nume și nota sunt variabile obișnuite.
fn main() {
let randuri = ["Ana: 9", "Mihai 8", "Ioana: zece", "Radu: 7"];
for rand in randuri {
let Some((nume, text)) = rand.split_once(':') else {
println!("rând fără ':' -> {rand}");
continue;
};
let Ok(nota) = text.trim().parse::<u8>() else {
println!("notă invalidă pentru {nume}");
continue;
};
println!("{nume} are nota {nota}");
}
}
Rezultat
Ana are nota 9
rând fără ':' -> Mihai 8
notă invalidă pentru Ioana
Radu are nota 7
Exemplul 3: Lanțuri if let … && (ediția 2024)
Condiția are trei părți: valoarea există, se poate transforma în număr și numărul este peste 18. Blocul se execută doar dacă toate sunt adevărate.
use std::collections::BTreeMap;
fn main() {
let mut date = BTreeMap::new();
date.insert("Ana", "21");
date.insert("Mihai", "16");
date.insert("Ioana", "nu știu");
for nume in ["Ana", "Mihai", "Ioana", "Radu"] {
if let Some(text) = date.get(nume)
&& let Ok(varsta) = text.parse::<u32>()
&& varsta >= 18
{
println!("{nume} ({varsta} ani) poate vota");
} else {
println!("{nume}: nu poate vota sau nu știm");
}
}
}
Rezultat
Ana (21 ani) poate vota
Mihai: nu poate vota sau nu știm
Ioana: nu poate vota sau nu știm
Radu: nu poate vota sau nu știm
Greșeli frecvente
- Blocul
elseal luilet ... elsenu iese din funcție: eroarea`else` clause of `let...else` does not diverge. Trebuie să se termine cureturn,break,continuesaupanic!. - Folosești
if letcu multe ramurielse if letpe aceeași valoare. Unmatcheste mai clar și verifică dacă ai tratat toate cazurile. - Folosești lanțuri
if let ... &&într-un proiect cu ediția 2021: nu se compilează. Lanțurile ceredition = "2024"înCargo.toml.
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.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.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.operatorul ?: Pus după un Result sau Option: dă valoarea dacă totul e bine, altfel returnează imediat eroarea (sau None) din funcția curentă.