00
:
00
:
00
:
00
•Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Match in Rust

L’espressione match è uno degli strumenti più potenti di Rust. Funziona in modo simile a uno switch di altri linguaggi, ma è molto più espressivo grazie al pattern matching. Il compilatore verifica che tutti i possibili casi siano gestiti, garantendo che nessun valore venga trascurato.

Match di base

La sintassi base confronta un valore con una serie di pattern. Ogni ramo (arm) è formato da un pattern, una freccia => e il codice da eseguire.

fn main() {
    let numero = 3;

    match numero {
        1 => println!("Uno"),
        2 => println!("Due"),
        3 => println!("Tre"),
        _ => println!("Altro numero"),
    }
}

Il simbolo _ è il pattern catch-all che corrisponde a qualsiasi valore non gestito dai rami precedenti. In Rust, il match deve essere esaustivo: ogni possibile valore deve essere coperto, altrimenti il codice non compila.

Pattern multipli con |

È possibile combinare più pattern in un singolo ramo usando l’operatore | (pipe).

fn main() {
    let giorno = "sabato";

    match giorno {
        "sabato" | "domenica" => println!("Weekend!"),
        "lunedi" | "martedi" | "mercoledi" | "giovedi" | "venerdi" => {
            println!("Giorno lavorativo")
        }
        _ => println!("Giorno non valido"),
    }
}

Pattern con range

I range permettono di verificare se un valore cade all’interno di un intervallo. Si usa la sintassi ..= per range inclusivi.

fn main() {
    let voto = 85;

    let giudizio = match voto {
        90..=100 => "Eccellente",
        80..=89 => "Buono",
        60..=79 => "Sufficiente",
        0..=59 => "Insufficiente",
        _ => "Voto non valido",
    };

    println!("Giudizio: {giudizio}");
}

I range funzionano con interi e caratteri:

fn main() {
    let lettera = 'c';

    match lettera {
        'a'..='f' => println!("Prima metà dell'alfabeto (a-f)"),
        'g'..='z' => println!("Seconda metà dell'alfabeto (g-z)"),
        _ => println!("Non è una lettera minuscola"),
    }
}

Catch-all con _

Il pattern _ corrisponde a qualsiasi valore senza vincolarlo a una variabile. È usato come ultimo ramo per gestire tutti i casi rimanenti.

fn main() {
    let codice = 404;

    match codice {
        200 => println!("OK"),
        404 => println!("Non trovato"),
        500 => println!("Errore del server"),
        _ => println!("Codice sconosciuto: {codice}"),
    }
}

Se non serve il catch-all ma si vuole catturare il valore, si può usare una variabile:

fn main() {
    let numero = 42;

    match numero {
        1 => println!("Uno"),
        2 => println!("Due"),
        altro => println!("Altro valore: {altro}"),
    }
}

Match come espressione

Come l’if, anche match è un’espressione e può restituire un valore.

fn main() {
    let dado = 4;

    let risultato = match dado {
        1 => "Uno",
        2 => "Due",
        3 => "Tre",
        4 => "Quattro",
        5 => "Cinque",
        6 => "Sei",
        _ => "Valore non valido",
    };

    println!("Hai tirato: {risultato}");
}

Tutti i rami devono restituire lo stesso tipo, altrimenti il compilatore segnalerà un errore.

Match con enum

Il match è particolarmente utile con le enum, dove il compilatore verifica che tutti i varianti siano gestiti.

enum Direzione {
    Nord,
    Sud,
    Est,
    Ovest,
}

fn descrivi_direzione(dir: Direzione) {
    match dir {
        Direzione::Nord => println!("Vai verso nord"),
        Direzione::Sud => println!("Vai verso sud"),
        Direzione::Est => println!("Vai verso est"),
        Direzione::Ovest => println!("Vai verso ovest"),
    }
}

fn main() {
    descrivi_direzione(Direzione::Nord);
}

Con enum che contengono dati, è possibile destrutturare i valori interni:

enum Messaggio {
    Testo(String),
    Numero(i32),
    Coordinate { x: f64, y: f64 },
}

fn gestisci_messaggio(msg: Messaggio) {
    match msg {
        Messaggio::Testo(t) => println!("Testo: {t}"),
        Messaggio::Numero(n) => println!("Numero: {n}"),
        Messaggio::Coordinate { x, y } => println!("Posizione: ({x}, {y})"),
    }
}

fn main() {
    gestisci_messaggio(Messaggio::Testo(String::from("Ciao")));
    gestisci_messaggio(Messaggio::Coordinate { x: 3.5, y: 7.2 });
}

Match con tuple e struct

Il pattern matching funziona anche con tuple e strutture.

fn main() {
    let punto = (0, -2);

    match punto {
        (0, 0) => println!("Origine"),
        (x, 0) => println!("Sull'asse X, x = {x}"),
        (0, y) => println!("Sull'asse Y, y = {y}"),
        (x, y) => println!("Punto generico: ({x}, {y})"),
    }
}

Con le struct, si usa la destrutturazione:

struct Punto {
    x: i32,
    y: i32,
}

fn main() {
    let p = Punto { x: 0, y: 5 };

    match p {
        Punto { x: 0, y: 0 } => println!("Origine"),
        Punto { x, y: 0 } => println!("Asse X: x = {x}"),
        Punto { x: 0, y } => println!("Asse Y: y = {y}"),
        Punto { x, y } => println!("Punto: ({x}, {y})"),
    }
}

Match guard

Le match guard aggiungono una condizione extra a un pattern tramite la parola chiave if. Questo permette di esprimere logiche più complesse.

fn main() {
    let numero = 4;

    match numero {
        n if n < 0 => println!("{n} è negativo"),
        n if n == 0 => println!("È zero"),
        n if n % 2 == 0 => println!("{n} è pari e positivo"),
        n => println!("{n} è dispari e positivo"),
    }
}

Le guard sono utili quando il pattern da solo non è sufficiente a esprimere la condizione desiderata:

fn main() {
    let temperatura = Some(38);

    match temperatura {
        Some(t) if t > 37 => println!("Febbre! Temperatura: {t}°C"),
        Some(t) => println!("Temperatura normale: {t}°C"),
        None => println!("Temperatura non rilevata"),
    }
}

Conclusione

L’espressione match è uno strumento fondamentale in Rust. Grazie alla sua esaustività controllata dal compilatore, al supporto per pattern complessi e alle match guard, permette di scrivere codice robusto e leggibile. Usa match ogni volta che hai bisogno di gestire più casi distinti, specialmente quando lavori con enum e tipi composti.