Vettori in Rust
Un vettore (Vec) è come un array, ma può crescere e rimpicciolirsi durante l’esecuzione. Nel codice Rust di tutti i giorni, quando ti serve una lista di cose, userai un Vec molto più spesso di un array a dimensione fissa.
Creare un vettore
Sezione intitolata “Creare un vettore”fn main() { let numbers: Vec<i32> = vec![1, 2, 3]; println!("{:?}", numbers);}vec![] è una macro (nota il !) che costruisce un Vec a partire da una lista di valori, un po’ come scriveresti un array letterale.
Puoi anche partire da un vettore vuoto e riempirlo man mano:
let mut numbers: Vec<i32> = Vec::new();Aggiungere elementi
Sezione intitolata “Aggiungere elementi”Usa .push() per aggiungere in fondo. Il vettore deve essere mut, perché lo stai modificando:
fn main() { let mut numbers = Vec::new();
numbers.push(1); numbers.push(2); numbers.push(3);
println!("{:?}", numbers);}Output:
[1, 2, 3]Leggere gli elementi
Sezione intitolata “Leggere gli elementi”Stessa sintassi con le parentesi quadre degli array:
fn main() { let fruits = vec!["mela", "banana", "ciliegia"];
println!("{}", fruits[0]); println!("Lunghezza: {}", fruits.len());}Per una lettura più sicura, che non va in panic con un indice sbagliato, usa .get(), che invece restituisce un Option (ne parliamo meglio nella pagina su Option):
fn main() { let fruits = vec!["mela", "banana", "ciliegia"];
match fruits.get(10) { Some(fruit) => println!("Trovato: {fruit}"), None => println!("Nessun frutto a quell'indice"), }}Togliere elementi
Sezione intitolata “Togliere elementi”fn main() { let mut numbers = vec![1, 2, 3, 4, 5];
numbers.pop(); // toglie l'ultimo elemento -> [1, 2, 3, 4] numbers.remove(0); // toglie per indice -> [2, 3, 4]
println!("{:?}", numbers);}Scorrere un vettore
Sezione intitolata “Scorrere un vettore”fn main() { let numbers = vec![10, 20, 30];
for n in &numbers { println!("{n}"); }}Nota la & prima di numbers: scorrendo con for n in &numbers prendi in prestito ogni elemento, invece di prendere possesso del vettore. Se togli la &, il vettore viene spostato dentro il ciclo, e dopo non puoi più usare numbers. Quasi sempre quello che vuoi è il prestito.
Due parole sui generici
Sezione intitolata “Due parole sui generici”Avrai notato che il tipo si scrive Vec<i32>: la parte <i32> dice «un vettore di valori i32». Questa notazione con le parentesi angolari si chiama generico (generic), e la vedrai per bene nella pagina sui Generici. Per ora leggi Vec<T> semplicemente come «un vettore che contiene valori di tipo T».
Pratica
Sezione intitolata “Pratica”1. Raccogli i numeri pari
Sezione intitolata “1. Raccogli i numeri pari”Parti da un vettore vuoto. Scorri i numeri da 1 a 10 e aggiungi solo quelli pari. Poi stampa il vettore e quanti elementi contiene. Suggerimento: un numero n è pari quando n % 2 == 0.
Mostra la soluzione
fn main() { let mut evens = Vec::new();
for n in 1..=10 { if n % 2 == 0 { evens.push(n); } }
println!("{:?}", evens); println!("Trovati {} numeri pari", evens.len());}Output:
[2, 4, 6, 8, 10]Trovati 5 numeri pariNota che non abbiamo mai scritto il tipo. Rust vede le chiamate push(n) e capisce da solo che evens è un Vec<i32>.
2. Una pila di piatti
Sezione intitolata “2. Una pila di piatti”Metti tre piatti in un vettore: "blu", "verde" e poi "rosso". Togli due piatti dalla cima con .pop() e stampali uno per uno. Infine stampa quello che resta. Suggerimento: .pop() restituisce un Option, quindi stampalo con {:?}.
Mostra la soluzione
fn main() { let mut plates = Vec::new(); plates.push("blu"); plates.push("verde"); plates.push("rosso");
println!("Preso {:?}", plates.pop()); println!("Preso {:?}", plates.pop()); println!("Rimasti: {:?}", plates);}Output:
Preso Some("rosso")Preso Some("verde")Rimasti: ["blu"]pop() prende sempre l’ultimo elemento che hai aggiunto, come quando prendi il piatto in cima alla pila. Restituisce Some(...) e non il valore semplice, perché il vettore potrebbe essere vuoto. In quel caso otterresti None invece di un crash.
Riepilogo
Sezione intitolata “Riepilogo”Vec<T>è una lista che può crescere; la crei convec![...]oVec::new()..push()aggiunge in fondo;.pop()toglie l’ultimo elemento;.remove(i)toglie per indice.vec[i]va in panic con un indice sbagliato;.get(i)invece restituisce unOptione non va in panic.- Scorri con
for elemento in &vecper prendere in prestito gli elementi invece di consumare il vettore.
Verifica veloce
Sezione intitolata “Verifica veloce”Verifica veloce
1. Che cosa succede se usi un indice sbagliato su un Vec, come numbers[10]?
2. Quale metodo ti permette di leggere un indice senza rischiare un panic?
3. Che cosa fa la & in for n in &numbers?
Punteggio: 0 / 3
Per approfondire
Sezione intitolata “Per approfondire”- Storing Lists of Values with Vectors — The Rust Book (in inglese): creare, leggere e aggiornare vettori, e perché non puoi fare push mentre tieni un riferimento.
- Vectors — Rust by Example (in inglese): un esempio eseguibile con le operazioni più comuni su
Vec. Vec— documentazione della libreria standard (in inglese): l’elenco completo dei metodi, comeinsert,retain,extendecontains.- La macro
vec!— documentazione della libreria standard (in inglese): tutte le forme divec!, compresovec![0; 10]per i valori ripetuti.