Option în Rust

Tipul care spune „poate există o valoare, poate nu”: Some(valoare) sau None, în locul lui null din alte limbaje.

Sintaxă
enum Option<T> {
    None,
    Some(T),
}

fn is_some(&self) -> bool
fn is_none(&self) -> bool

Ce face Option

Rust nu are null. Când o valoare poate lipsi (căutarea unui elev după nume, primul element al unui vector gol, un câmp opțional), funcția returnează Option<T>. Valoarea este fie Some(x), adică există și este x, fie None, adică lipsește.

Compilatorul nu te lasă să folosești direct valoarea din Some: trebuie să tratezi și cazul None. Cel mai clar faci asta cu match sau cu if let Some(x) = .... Pentru o întrebare simplă de tip da/nu există is_some() (este Some?) și is_none() (este None?).

Option, Some și None sunt incluse automat în orice program (fac parte din prelude), deci nu ai nevoie de use.

Parametri

Parametru Descriere
T Tipul valorii care poate lipsi: Option<i32>, Option<String>, Option<&str> etc.

Ce returnează

is_some() returnează true pentru Some(_); is_none() returnează true pentru None.

Exemple

Exemplul 1: O funcție care poate să nu găsească nimic

cauta_nota returnează Some(nota) dacă elevul există și None altfel. match tratează ambele cazuri.

fn cauta_nota(nume: &str) -> Option<u8> {
    match nume {
        "Ana" => Some(10),
        "Mihai" => Some(8),
        _ => None,
    }
}

fn main() {
    for elev in ["Ana", "Ioana", "Mihai"] {
        match cauta_nota(elev) {
            Some(nota) => println!("{elev} are nota {nota}"),
            None => println!("{elev} nu are încă notă"),
        }
    }
}

Rezultat

Ana are nota 10
Ioana nu are încă notă
Mihai are nota 8

Exemplul 2: is_some, is_none și if let

Metodele din std returnează și ele Option: first() pe un vector gol dă None. Cu {:?} vezi exact ce conține opțiunea.

fn main() {
    let orase = vec!["Iași", "Cluj", "Brașov"];
    let goale: Vec<&str> = Vec::new();

    let primul = orase.first();
    let nimic = goale.first();

    println!("primul = {primul:?}, is_some = {}", primul.is_some());
    println!("nimic = {nimic:?}, is_none = {}", nimic.is_none());

    if let Some(oras) = orase.get(2) {
        println!("Al treilea oraș: {oras}");
    }
    if orase.get(10).is_none() {
        println!("Nu există poziția 10");
    }
}

Rezultat

primul = Some("Iași"), is_some = true
nimic = None, is_none = true
Al treilea oraș: Brașov
Nu există poziția 10

Greșeli frecvente

  • Încerci să folosești direct valoarea: let n: u8 = cauta_nota("Ana"); nu compilează, pentru că rezultatul este Option<u8>, nu u8. Scoate valoarea cu match, if let, unwrap_or sau ?.
  • Scrii if x.is_some() { let v = x.unwrap(); ... }. Merge, dar if let Some(v) = x { ... } face același lucru mai scurt și fără risc de panică.
  • Folosești o valoare specială (0, -1, șir gol) pentru „lipsă”. În Rust, Option face lipsa vizibilă în tip și compilatorul te obligă să o tratezi.

Comenzi înrudite

  • Option::unwrap: Scoate valoarea din Some; pentru None programul se oprește cu panică. expect face la fel, cu mesajul tău.
  • Option::unwrap_or: Scoate valoarea din Some sau, pentru None, folosește o valoare de rezervă: fixă, calculată de o funcție sau implicită.
  • Option::map: Transformă valoarea din Some cu o funcție și păstrează None neschimbat.
  • Option::ok_or: Transformă un Option în Result: Some(x) devine Ok(x), iar None devine Err cu eroarea dată.
  • Result: Tipul pentru operații care pot eșua: Ok(valoare) la succes sau Err(eroare) cu motivul eșecului.