Vai al contenuto
eLearner.app
Modulo 2 · Lezione 2 di 24/14 nel corso~15 min
Lezioni del modulo (2/2)

Pattern matching, Option e Result

Rust possiede un meccanismo di controllo del flusso estremamente potente chiamato pattern matching. Permette di confrontare un valore con una serie di pattern ed eseguire codice in base al pattern corrispondente.

L'Istruzione match

L'istruzione match in Rust è simile allo switch in altri linguaggi, ma molto più potente e sicura. Il compilatore garantisce che il matching sia esaustivo, ossia che tutti i possibili casi siano gestiti:

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"),
}

Gestire l'assenza di valore: Option

Rust non ha il concetto di valore nullo (null o nil). Al suo posto, la libreria standard definisce un enum chiamato Option<T> che può contenere:

  • Some(T): contiene un valore di tipo T.
  • None: indica l'assenza di valore.
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"),
}

Gestire gli errori ripristinabili: Result

Per operazioni che possono fallire (come la lettura di un file o la conversione di una stringa in numero), Rust usa l'enum Result<T, E> che possiede due varianti:

  • Ok(T): l'operazione è andata a buon fine e contiene il valore di successo T.
  • Err(E): l'operazione è fallita e contiene l'errore 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)
    }
}

Grazie al compilatore di Rust, sei obbligato a gestire il caso Err prima di poter accedere al valore dentro Ok, evitando moltissimi bug a runtime.

Il Pattern Jolly _ (Wildcard)

Quando lavoriamo con tipi di dato che hanno un gran numero di varianti (come gli interi), elencare tutti i casi in un match è impossibile. Rust permette di usare il carattere jolly _ per catturare tutti i casi rimanenti non definiti esplicitamente:

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

Prova tu

Esercizio#rust.m2.l2.e1
Tentativi: 0Caricamento…

Dichiara una variabile maybe_value di tipo Option<i32> contenente Some(42). Usa un'istruzione match su maybe_value: se contiene Some(v) stampa 'value is: v' (con println!), se contiene None stampa 'no value'.

Caricamento editor…
Mostra suggerimento

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

Soluzione disponibile dopo 3 tentativi

Esercizio#rust.m2.l2.e2
Tentativi: 0Caricamento…

Completa la funzione check_age in modo che restituisca Ok('Adult') se age è maggiore o uguale a 18, oppure Err('Minor') in caso contrario.

Caricamento editor…
Mostra suggerimento

Usa un `if age >= 18`per decidere se restituire`Ok('Adult')`oppure`Err('Minor')`.

Soluzione disponibile dopo 3 tentativi

Esercizio#rust.m2.l2.e3
Tentativi: 0Caricamento…

Dichiara un enum chiamato Status contenente le varianti Active e Inactive. Nel main, dichiara una variabile current_status con valore Status::Active. Infine, usa un'istruzione match su current_status per stampare 'active' se lo stato è Active, o 'inactive' se lo stato è Inactive.

Caricamento editor…
Mostra suggerimento

Definisci l'enum prima del main con `enum Status { Active, Inactive }`. Nel main usa `let current_status = Status::Active;`ed esegui il`match` sulle varianti.

Soluzione disponibile dopo 3 tentativi