Przejdź do głównej treści
eLearner.app
Moduł 2 · Lekcja 2 z 24/14 w kursie~15 min
Lekcje modułu (2/2)

Dopasowanie wzorców, Option i Result

Rust posiada niezwykle potężny mechanizm sterowania przepływem zwany dopasowywaniem wzorców (pattern matching). Pozwala on na porównanie wartości z serią wzorców i wykonanie kodu na podstawie dopasowanego wzorca.

Instrukcja match

Instrukcja match w języku Rust przypomina switch znany z innych języków, ale jest znacznie potężniejsza i bezpieczniejsza. Kompilator gwarantuje, że dopasowanie jest wyczerpujące (esaustivo), co oznacza, że wszystkie możliwe przypadki muszą zostać obsłużone:

Code
enum Direction {
    North,
    South,
    East,
    West,
}

let dir = Direction::East;

match dir {
    Direction::North => println!("Andiamo a Nord"),
    Direction::South => println!("Andiamo a Sud"),
    Direction::East => println!("Andiamo a Est"),
    Direction::West => println!("Andiamo a Ovest"),
}

Obsługa braku wartości: Option

Rust nie posiada pojęcia wartości pustej (null lub nil). Zamiast tego biblioteka standardowa definiuje typ wyliczeniowy (enum) o nazwie Option<T>, który może zawierać:

  • Some(T): zawiera wartość typu T.
  • None: oznacza brak wartości.
Code
let x: Option<i32> = Some(5);
let y: Option<i32> = None;

match x {
    Some(val) => println!("C'e un valore: {}", val),
    None => println!("Nessun valore trovato"),
}

Obsługa błędów odwracalnych: Result

W przypadku operacji, które mogą się nie powieść (np. odczyt pliku lub konwersja tekstu na liczbę), Rust używa typu wyliczeniowego Result<T, E>, który posiada dwa warianty:

  • Ok(T): operacja zakończyła się sukcesem i zawiera pomyślnie uzyskaną wartość T.
  • Err(E): operacja nie powiodła się i zawiera błąd E.
Code
fn divide(numerator: f64, denominator: f64) -> Result<f64, String> {
    if denominator == 0.0 {
        Err(String::from("Divisione per zero!"))
    } else {
        Ok(numerator / denominator)
    }
}

Dzięki kompilatorowi Rusta jesteś zobowiązany do obsłużenia przypadku Err zanim uzyskasz dostęp do wartości wewnątrz Ok, co zapobiega wielu błędom w czasie wykonywania programu.

Wzorzec wieloznaczny _ (Wildcard)

Podczas pracy z typami danych posiadającymi bardzo dużą liczbę wariantów (jak liczby całkowite), wymienienie wszystkich przypadków w instrukcji match jest niemożliwe. Rust pozwala na użycie znaku wieloznacznego _ w celu przechwycenia wszystkich pozostałych, jawnie niezdefiniowanych przypadków:

Code
let some_u8 = 3u8;
match some_u8 {
    1 => println!("Uno"),
    2 => println!("Due"),
    _ => println!("Qualcos'altro"), // Gestisce tutti gli altri valori
}

Spróbuj sam

Ćwiczenie#rust.m2.l2.e1
Próby: 0Ładowanie...

Zadeklaruj zmienną maybe_value typu Option<i32> zawierającą Some(42). Użyj instrukcji match na maybe_value: jeśli zawiera Some(v) wypisz 'value is: v' (za pomocą println!), jeśli zawiera None wypisz 'no value'.

Ładowanie edytora...
Pokaż wskazówkę

Zapisz blok `match maybe_value { Some(v) => println!('value is: {}', v), None => println!('no value') }`.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#rust.m2.l2.e2
Próby: 0Ładowanie...

Uzupełnij funkcję check_age tak, aby zwracała Ok('Adult'), jeśli age jest większe lub równe 18, lub Err('Minor') w przeciwnym razie.

Ładowanie edytora...
Pokaż wskazówkę

Użyj `if age >= 18`do podjęcia decyzji, czy zwrócić`Ok('Adult')`czy`Err('Minor')`.

Rozwiązanie dostępne po 3 próbach

Ćwiczenie#rust.m2.l2.e3
Próby: 0Ładowanie...

Zadeklaruj enum o nazwie Status zawierający warianty Active i Inactive. W funkcji main zadeklaruj zmienną current_status o wartości Status::Active. Na koniec użyj instrukcji match na current_status, aby wypisać 'active', jeśli status to Active, lub 'inactive', jeśli status to Inactive.

Ładowanie edytora...
Pokaż wskazówkę

Zdefiniuj enum przed funkcją main za pomocą `enum Status { Active, Inactive }`. W main użyj `let current_status = Status::Active;`i wykonaj dopasowanie`match` na wariantach.

Rozwiązanie dostępne po 3 próbach