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

Tuple in Rust

Le tuple in Rust sono un tipo di dato composto che permette di raggruppare un numero fisso di valori di tipi diversi in un’unica struttura. Sono particolarmente utili quando si vuole restituire più valori da una funzione o raggruppare dati correlati senza definire una struct completa.

Creare una Tupla

Una tupla si crea racchiudendo i valori tra parentesi tonde, separati da virgole. Il tipo viene inferito automaticamente dal compilatore, ma può anche essere annotato esplicitamente.

fn main() {
    // Tupla con tipo inferito
    let punto = (10, 20);

    // Tupla con annotazione esplicita del tipo
    let persona: (&str, i32, f64) = ("Marco", 30, 1.82);

    // Tupla con tipi misti
    let dati: (i32, f64, bool, char) = (42, 3.14, true, 'R');

    println!("Punto: {:?}", punto);
    println!("Persona: {:?}", persona);
    println!("Dati: {:?}", dati);
}

Accesso agli Elementi con la Notazione a Punto

Per accedere ai singoli elementi di una tupla si usa la notazione a punto seguita dall’indice numerico, partendo da 0.

fn main() {
    let colore = (255, 128, 0);

    let rosso = colore.0;
    let verde = colore.1;
    let blu = colore.2;

    println!("R: {}, G: {}, B: {}", rosso, verde, blu);
}

Questa notazione è valida solo con indici letterali noti a tempo di compilazione: non e possibile usare una variabile come indice.

Destrutturazione delle Tuple

La destrutturazione consente di estrarre tutti i valori di una tupla in variabili separate con un’unica istruzione. Si tratta di una delle operazioni piu comuni e idiomatiche in Rust.

fn main() {
    let coordinate = (45.4642, 9.1900);

    let (latitudine, longitudine) = coordinate;

    println!("Latitudine: {}", latitudine);
    println!("Longitudine: {}", longitudine);
}

Se non servono tutti i valori, si puo usare _ per ignorare quelli non necessari:

fn main() {
    let dati = ("Rust", 2024, true);

    let (nome, _, attivo) = dati;

    println!("{} attivo: {}", nome, attivo);
}

Tuple come Valore di Ritorno di Funzioni

Le tuple sono estremamente utili per restituire piu valori da una funzione senza dover definire una struct dedicata.

fn dividi_con_resto(dividendo: i32, divisore: i32) -> (i32, i32) {
    let quoziente = dividendo / divisore;
    let resto = dividendo % divisore;
    (quoziente, resto)
}

fn main() {
    let (q, r) = dividi_con_resto(17, 5);
    println!("17 / 5 = {} con resto {}", q, r);
}

Un altro esempio pratico che restituisce il minimo e il massimo di un vettore:

fn min_max(valori: &[i32]) -> (i32, i32) {
    let mut minimo = valori[0];
    let mut massimo = valori[0];
    for &v in &valori[1..] {
        if v < minimo { minimo = v; }
        if v > massimo { massimo = v; }
    }
    (minimo, massimo)
}

fn main() {
    let numeri = vec![3, 7, 1, 9, 4];
    let (min, max) = min_max(&numeri);
    println!("Minimo: {}, Massimo: {}", min, max);
}

La Tupla Unitaria ()

La tupla vuota () e chiamata unit type ed e il tipo di ritorno implicito di ogni funzione che non restituisce un valore. In Rust, corrisponde concettualmente a void di altri linguaggi.

fn saluta(nome: &str) {
    println!("Ciao, {}!", nome);
    // Il tipo di ritorno implicito e ()
}

fn main() {
    let risultato: () = saluta("Mondo");
    println!("Risultato: {:?}", risultato); // Stampa: ()
}

Confronto tra Tuple

Le tuple implementano i trait PartialEq e PartialOrd se tutti i loro elementi li implementano. Il confronto avviene elemento per elemento, da sinistra a destra.

fn main() {
    let a = (1, 2, 3);
    let b = (1, 2, 3);
    let c = (1, 3, 2);

    println!("a == b: {}", a == b); // true
    println!("a == c: {}", a == c); // false
    println!("a < c: {}", a < c);   // true (confronta il secondo elemento)

    // Confronto lessicografico
    let x = ("alfa", 1);
    let y = ("beta", 0);
    println!("x < y: {}", x < y); // true ("alfa" < "beta")
}

Le tuple possono essere confrontate solo fino a una lunghezza massima di 12 elementi con i trait standard della libreria.

Tuple Annidate

Le tuple possono contenere altre tuple, permettendo strutture dati piu articolate:

fn main() {
    let matrice = ((1, 2), (3, 4));

    println!("Elemento [0][1]: {}", (matrice.0).1); // 2
    println!("Elemento [1][0]: {}", (matrice.1).0); // 3

    // Destrutturazione annidata
    let ((a, b), (c, d)) = matrice;
    println!("Valori: {} {} {} {}", a, b, c, d);
}

Conclusione

Le tuple in Rust sono uno strumento semplice ma potente per raggruppare valori eterogenei. La notazione a punto per l’accesso, la destrutturazione idiomatica e la possibilita di usarle come tipo di ritorno delle funzioni le rendono una scelta naturale in molti scenari. Per dati piu strutturati o con significato semantico chiaro, e preferibile passare a una struct, ma le tuple rimangono ideali per raggruppamenti temporanei e veloci.