Result::and_then în Rust

and_then continuă cu următorul pas care poate eșua doar dacă cel curent a reușit; or_else încearcă o recuperare la eroare.

Sintaxă
fn and_then<U, F: FnOnce(T) -> Result<U, E>>(self, op: F) -> Result<U, E>
fn or_else<F, O: FnOnce(E) -> Result<T, F>>(self, op: O) -> Result<T, F>

Ce face Result::and_then

and_then aplică funcția pe valoarea din Ok; funcția returnează la rândul ei un Result. Prima eroare oprește lanțul și este returnată ca atare.

or_else este pentru partea de eroare: dacă rezultatul este Err(e), apelează funcția cu e, care poate „repara” situația (returnează Ok) sau poate da altă eroare. Pentru Ok, funcția nu este apelată.

Parametri

Parametru Descriere
op La and_then: pasul următor, aplicat valorii. La or_else: recuperarea, aplicată erorii.

Ce returnează

Un Result: rezultatul pasului următor, respectiv al recuperării.

Exemple

Exemplul 1: Validare în doi pași

Întâi transformăm textul în număr, apoi verificăm intervalul. Fiecare pas poate da eroare.

fn in_interval(n: i32) -> Result<i32, String> {
    if (1..=10).contains(&n) {
        Ok(n)
    } else {
        Err(format!("{n} nu este între 1 și 10"))
    }
}

fn main() {
    for t in ["7", "15", "x"] {
        let r = t
            .parse::<i32>()
            .map_err(|e| e.to_string())
            .and_then(in_interval);
        println!("{t:?} -> {r:?}");
    }
}

Rezultat

"7" -> Ok(7)
"15" -> Err("15 nu este între 1 și 10")
"x" -> Err("invalid digit found in string")

Exemplul 2: Recuperare cu or_else

Dacă textul nu este un număr întreg, încercăm să-l citim ca număr zecimal și îl rotunjim.

fn citeste(text: &str) -> Result<i64, String> {
    text.parse::<i64>().or_else(|_| {
        text.parse::<f64>()
            .map(|f| f.round() as i64)
            .map_err(|_| format!("„{text}” nu este număr"))
    })
}

fn main() {
    for t in ["12", "12.7", "doisprezece"] {
        println!("{t:?} -> {:?}", citeste(t));
    }
}

Rezultat

"12" -> Ok(12)
"12.7" -> Ok(13)
"doisprezece" -> Err("„doisprezece” nu este număr")

Greșeli frecvente

  • Folosești and_then când tipurile de eroare diferă între pași: toate trebuie să aibă același E. Unifică-le cu map_err.
  • Faci lanțuri lungi de and_then. Într-o funcție care returnează Result, varianta cu ? pe fiecare linie este mai ușor de citit.

Comenzi înrudite

  • Result::map: map transformă valoarea din Ok și lasă eroarea neschimbată; map_err transformă eroarea și lasă valoarea neschimbată.
  • Option::and_then: Leagă mai mulți pași care pot da None: aplică funcția doar pentru Some, iar funcția returnează la rândul ei un Option.
  • Option::or: Dacă opțiunea este None, încearcă altă opțiune; Some rămâne neschimbat. or_else calculează alternativa doar la nevoie.
  • Result: Tipul pentru operații care pot eșua: Ok(valoare) la succes sau Err(eroare) cu motivul eșecului.