Ce face enum
Un enum enumeră toate formele posibile ale unei valori. Spre deosebire de enum-urile din C sau Java, fiecare variantă poate purta date diferite: Mesaj::Text(String), Mesaj::Locatie { lat: f64, lon: f64 }, Mesaj::Iesire. O valoare de tipul enum este întotdeauna exact una dintre variante.
Valoarea se folosește cu match, care obligă să tratezi fiecare variantă și scoate datele din ea. Poți adăuga metode cu impl, ca la structuri. Două enum-uri din biblioteca standard sunt peste tot: Option<T> (Some(x) sau None, în locul lui null) și Result<T, E> (Ok(x) sau Err(e), în locul excepțiilor).
Un enum doar cu variante fără date funcționează ca în C: fiecare variantă are un număr (implicit 0, 1, 2…, sau dat explicit cu = 3), obținut cu as i32.
Exemple
Exemplul 1: Variante cu date diferite
Fiecare comandă dintr-un magazin online este într-una dintre trei stări, iar fiecare stare are datele ei. Metoda descriere folosește match ca să trateze toate stările.
enum Stare {
InAsteptare,
Expediata { curier: String, awb: u64 },
Livrata(String),
}
impl Stare {
fn descriere(&self) -> String {
match self {
Stare::InAsteptare => "în așteptare".to_string(),
Stare::Expediata { curier, awb } => format!("expediată prin {curier}, AWB {awb}"),
Stare::Livrata(data) => format!("livrată pe {data}"),
}
}
}
fn main() {
let comenzi = vec![
(1001, Stare::Livrata("12.10.2026".to_string())),
(1002, Stare::Expediata { curier: "FAN".to_string(), awb: 2_345_678_901 }),
(1003, Stare::InAsteptare),
];
for (nr, stare) in &comenzi {
println!("Comanda {nr}: {}", stare.descriere());
}
}
Rezultat
Comanda 1001: livrată pe 12.10.2026
Comanda 1002: expediată prin FAN, AWB 2345678901
Comanda 1003: în așteptare
Exemplul 2: Option: valoare care poate lipsi
Option este un enum obișnuit cu variantele Some și None. Funcția returnează None când elevul nu există, iar apelantul este obligat să trateze cazul.
fn nota(elev: &str) -> Option<u8> {
match elev {
"Ana" => Some(10),
"Mihai" => Some(8),
_ => None,
}
}
fn main() {
for elev in ["Ana", "Radu"] {
match nota(elev) {
Some(n) => println!("{elev}: {n}"),
None => println!("{elev}: nu are notă"),
}
}
println!("{:?} {:?}", nota("Mihai"), nota("Ioana"));
}
Rezultat
Ana: 10
Radu: nu are notă
Some(8) None
Exemplul 3: Enum ca în C, cu valori numerice
Variantele au valori explicite. as u8 dă numărul, iar #[derive(PartialEq, PartialOrd)] permite compararea lor.
#[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
enum Prioritate {
Scazuta = 1,
Medie = 5,
Urgenta = 10,
}
fn main() {
let p = Prioritate::Medie;
println!("{p:?} = {}", p as u8);
println!("Urgentă > medie: {}", Prioritate::Urgenta > p);
println!("Scăzută == medie: {}", Prioritate::Scazuta == p);
}
Rezultat
Medie = 5
Urgentă > medie: true
Scăzută == medie: false
Greșeli frecvente
- Scrii varianta fără numele enum-ului (
Livrata(...)în loc deStare::Livrata(...)). Fărăuse Stare::*;, variantele trebuie prefixate. - Folosești valori „speciale” (-1, șir gol) pentru „lipsă”, ca în alte limbaje. În Rust, pentru o valoare care poate lipsi folosește
Option, iar pentru operații care pot eșuaResult. - Compari variante cu
==fără#[derive(PartialEq)]. Pentru o simplă verificare a variantei,matches!(stare, Stare::InAsteptare)funcționează și fărăPartialEq.
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.struct: Definește un tip nou care grupează mai multe valori cu nume (câmpuri), de exemplu un elev cu nume, clasă și medie.impl, self și Self: impl adaugă metode și funcții asociate unui tip; self este valoarea pe care se apelează metoda, iar Self este tipul însuși.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.matches!: Returnează true dacă o valoare se potrivește cu un tipar (ca într-o ramură de match) și false altfel.