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.