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: arraytuplevettori 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

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, arraytuplevettori 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.
  • 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!