Option::and_then în Rust

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.

Sintaxă
fn and_then<U, F: FnOnce(T) -> Option<U>>(self, f: F) -> Option<U>

Ce face Option::and_then

and_then seamănă cu map, dar funcția dată returnează un Option. Astfel poți înlănțui pași care pot eșua fiecare: dacă oricare dă None, rezultatul final este None și pașii următori nu mai rulează.

Rezultatul nu este „împachetat de două ori”: dacă funcția returnează Some(y), obții Some(y), nu Some(Some(y)). În alte limbaje operația se numește flatMap sau bind.

Într-o funcție care returnează ea însăși Option, aceeași înlănțuire se scrie adesea mai clar cu operatorul ?.

Parametri

Parametru Descriere
f Funcția aplicată valorii din Some; returnează Option<U>.

Ce returnează

None dacă opțiunea este None; altfel, exact ce returnează f(x).

Exemple

Exemplul 1: Pași care pot eșua fiecare

Întâi găsim elevul, apoi îi citim nota. Al doilea pas returnează și el Option, deci folosim and_then.

fn id_elev(nume: &str) -> Option<u32> {
    match nume {
        "Ana" => Some(1),
        "Mihai" => Some(2),
        _ => None,
    }
}

fn nota_dupa_id(id: u32) -> Option<u8> {
    if id == 1 { Some(10) } else { None }
}

fn main() {
    for nume in ["Ana", "Mihai", "Ioana"] {
        let nota = id_elev(nume).and_then(nota_dupa_id);
        println!("{nume}: {nota:?}");
    }
}

Rezultat

Ana: Some(10)
Mihai: None
Ioana: None

Exemplul 2: Diferența față de map

Cu map, funcția care returnează Option dă un Option în Option; and_then îl „aplatizează”.

fn main() {
    let text: Option<&str> = Some("42");

    let cu_map: Option<Option<i32>> = text.map(|t| t.parse().ok());
    let cu_and_then: Option<i32> = text.and_then(|t| t.parse().ok());

    println!("map:      {cu_map:?}");
    println!("and_then: {cu_and_then:?}");

    let gresit: Option<&str> = Some("patru");
    println!("text invalid: {:?}", gresit.and_then(|t| t.parse::<i32>().ok()));
}

Rezultat

map:      Some(Some(42))
and_then: Some(42)
text invalid: None

Greșeli frecvente

  • Folosești and_then cu o funcție care returnează o valoare simplă: nu compilează. Pentru asta e map.
  • Faci lanțuri foarte lungi de and_then cu closure-uri imbricate. Într-o funcție care returnează Option, operatorul ? este mai ușor de citit.

Comenzi înrudite

  • Option::map: Transformă valoarea din Some cu o funcție și păstrează None neschimbat.
  • Option::or: Dacă opțiunea este None, încearcă altă opțiune; Some rămâne neschimbat. or_else calculează alternativa doar la nevoie.
  • Result::and_then: 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.
  • Option::filter: filter păstrează valoarea doar dacă respectă o condiție; is_some_and întreabă direct dacă există și respectă condiția.