Rust è un linguaggio di programmazione moderno che combina prestazioni elevate con sicurezza della memoria. Una delle caratteristiche che rendono Rust così potente è il suo sistema di tipi e la gestione efficiente delle strutture dati. In questo articolo, esploreremo quattro strutture dati fondamentali in Rust: array, tuple, vettori e slice. Queste strutture sono ampiamente utilizzate per memorizzare e manipolare collezioni di dati, e comprendere come funzionano è essenziale per scrivere codice Rust efficace.
1. Array in Rust
Gli array in Rust sono collezioni di dimensione fissa di elementi dello stesso tipo. La dimensione di un array è determinata al momento della compilazione e non può essere modificata durante l’esecuzione del programma.
Dichiarazione e Inizializzazione
Un array viene dichiarato specificando il tipo degli elementi e la dimensione dell’array. Ecco un esempio:
let numeri: [i32; 5] = [1, 2, 3, 4, 5];
In questo caso, numeri
è un array di 5 elementi di tipo i32
. La sintassi [T; N]
indica un array di tipo T
con N
elementi.
Accesso agli Elementi
Gli elementi di un array sono accessibili tramite indici, che partono da 0
:
let primo = numeri[0]; // Accesso al primo elemento
let secondo = numeri[1]; // Accesso al secondo elemento
Modifica degli Elementi
Gli array in Rust sono immutabili per default. Per modificarli, è necessario dichiararli come mutabili:
let mut numeri = [1, 2, 3, 4, 5];
numeri[0] = 10; // Modifica del primo elemento
Iterazione su un Array
Per iterare su un array, si può usare un ciclo for
:
for numero in numeri.iter() {
println!("{}", numero);
}
In alternativa, si può usare un ciclo for
con indici:
for i in 0..numeri.len() {
println!("{}", numeri[i]);
}
Limitazioni degli Array
- La dimensione è fissa e deve essere nota al momento della compilazione.
- Non è possibile aggiungere o rimuovere elementi.
2. Tuple in Rust
Le tuple sono collezioni eterogenee di dimensioni fisse, che possono contenere elementi di tipi diversi. Sono utili per raggruppare valori correlati senza dover definire una struttura personalizzata.
Dichiarazione e Inizializzazione
Una tuple viene dichiarata elencando i valori tra parentesi tonde:
let persona: (&str, i32, bool) = ("Alice", 30, true);
In questo esempio, persona
è una tuple che contiene una stringa (&str
), un intero (i32
) e un booleano (bool
).
Accesso agli Elementi
Gli elementi di una tuple sono accessibili tramite l’operatore .
seguito dall’indice:
let nome = persona.0; // Accesso al primo elemento ("Alice")
let eta = persona.1; // Accesso al secondo elemento (30)
Destrutturazione di una Tuple
Rust permette di “destrutturare” una tuple per assegnare i suoi valori a variabili separate:
let (nome, eta, is_student) = persona;
println!("Nome: {}, Età: {}, Studente: {}", nome, eta, is_student);
Utilizzo delle Tuple
Le tuple sono spesso utilizzate per restituire più valori da una funzione:
fn calcola_operazioni(a: i32, b: i32) -> (i32, i32) {
(a + b, a * b)
}
let (somma, prodotto) = calcola_operazioni(3, 4);
3. Vettori in Rust
I vettori (Vec<T>
) sono collezioni dinamiche di elementi dello stesso tipo. A differenza degli array, i vettori possono crescere o ridursi durante l’esecuzione del programma.
Dichiarazione e Inizializzazione
Un vettore viene creato utilizzando la macro vec!
o il costruttore Vec::new()
:
let mut numeri = vec![1, 2, 3, 4, 5]; // Utilizzo della macro vec!
let mut vuoto: Vec<i32> = Vec::new(); // Creazione di un vettore vuoto
Aggiunta di Elementi
È possibile aggiungere elementi a un vettore utilizzando il metodo push
:
numeri.push(6); // Aggiunge 6 alla fine del vettore
Accesso agli Elementi
Gli elementi di un vettore sono accessibili tramite indici:
let primo = numeri[0]; // Accesso al primo elemento
Attenzione: l’accesso a un indice fuori dai limiti del vettore causerà un panic. Per un accesso sicuro, si può usare il metodo get
:
if let Some(valore) = numeri.get(10) {
println!("{}", valore);
} else {
println!("Indice fuori dai limiti");
}
Iterazione su un Vettore
Per iterare su un vettore, si può usare un ciclo for
:
for numero in &numeri {
println!("{}", numero);
}
Rimozione di Elementi
È possibile rimuovere elementi da un vettore utilizzando il metodo pop
, che rimuove l’ultimo elemento:
let ultimo = numeri.pop(); // Rimuove e restituisce l'ultimo elemento
4. Slice in Rust
Le slice sono riferimenti a una porzione contigua di una collezione, come un array o un vettore. Non possiedono i dati, ma permettono di accedere a una parte di essi.
Dichiarazione e Utilizzo
Una slice viene creata utilizzando un riferimento a un array o a un vettore:
let numeri = [1, 2, 3, 4, 5];
let slice: &[i32] = &numeri[1..4]; // Slice che include gli elementi 2, 3, 4
In questo caso, slice
è un riferimento agli elementi dall’indice 1
all’indice 3
(escluso).
Slice di Vettori
Le slice possono essere create anche da vettori:
let numeri = vec![1, 2, 3, 4, 5];
let slice: &[i32] = &numeri[1..4];
Iterazione su una Slice
Le slice supportano l’iterazione come gli array e i vettori:
for valore in slice {
println!("{}", valore);
}
Utilizzo delle Slice
Le slice sono utili per passare una parte di una collezione a una funzione senza copiare i dati:
fn stampa_slice(slice: &[i32]) {
for valore in slice {
println!("{}", valore);
}
}
stampa_slice(&numeri[1..4]);
Conclusioni
In Rust, array, tuple, vettori e slice sono strumenti potenti per gestire collezioni di dati. Ognuno di essi ha caratteristiche uniche:
- Gli array sono ideali per collezioni di dimensione fissa.
- Le tuple sono utili per raggruppare valori eterogenei.
- I vettori offrono flessibilità per collezioni dinamiche.
- Le slice permettono di lavorare con porzioni di dati in modo efficiente.
Comprendere queste strutture dati è fondamentale per scrivere codice Rust efficiente e sicuro. Con questa conoscenza, sei pronto per utilizzare array, tuple, vettori e slice nei tuoi progetti Rust!