Salta ai contenuti

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.

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.

▶ Provalo tu

Puoi anche partire da un vettore vuoto e riempirlo man mano:

let mut numbers: Vec<i32> = Vec::new();

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]
▶ Provalo tu

Stessa sintassi con le parentesi quadre degli array:

fn main() {
let fruits = vec!["mela", "banana", "ciliegia"];
println!("{}", fruits[0]);
println!("Lunghezza: {}", fruits.len());
}
▶ Provalo tu

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"),
}
}
▶ Provalo tu
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);
}
▶ Provalo tu
fn main() {
let numbers = vec![10, 20, 30];
for n in &numbers {
println!("{n}");
}
}
▶ Provalo tu

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.

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».

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 pari
▶ Provalo tu

Nota che non abbiamo mai scritto il tipo. Rust vede le chiamate push(n) e capisce da solo che evens è un Vec<i32>.

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"]
▶ Provalo tu

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.

  • Vec<T> è una lista che può crescere; la crei con vec![...] o Vec::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 un Option e non va in panic.
  • Scorri con for elemento in &vec per prendere in prestito gli elementi invece di consumare il vettore.

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