Vettori in Rust
Vec<T> è il tipo di collezione dinamica più utilizzato in Rust. A differenza degli array, i vettori possono crescere e ridursi a runtime e sono allocati sullo heap.
Creare un Vettore
fn main() {
// Con Vec::new()
let mut numeri: Vec<i32> = Vec::new();
// Con la macro vec!
let numeri = vec![1, 2, 3, 4, 5];
// Con valore ripetuto
let zeri = vec![0; 10]; // 10 zeri
// Con capacità pre-allocata
let mut buffer = Vec::with_capacity(100);
}
Aggiungere Elementi
fn main() {
let mut v = Vec::new();
v.push(1);
v.push(2);
v.push(3);
// Aggiungere più elementi
v.extend([4, 5, 6]);
// Inserire a una posizione specifica
v.insert(0, 0); // [0, 1, 2, 3, 4, 5, 6]
println!("{:?}", v);
}
Accesso agli Elementi
fn main() {
let v = vec![10, 20, 30, 40, 50];
// Con indice (panic se fuori range)
println!("{}", v[0]); // 10
// Con get (restituisce Option)
match v.get(10) {
Some(val) => println!("{}", val),
None => println!("Indice fuori range"),
}
// Primo e ultimo
println!("{:?}", v.first()); // Some(10)
println!("{:?}", v.last()); // Some(50)
}
Rimuovere Elementi
fn main() {
let mut v = vec![1, 2, 3, 4, 5];
let ultimo = v.pop(); // Some(5), v = [1, 2, 3, 4]
let secondo = v.remove(1); // 2, v = [1, 3, 4]
v.swap_remove(0); // Rimuove indice 0, veloce ma non mantiene l'ordine
// Rimuovere con condizione
v.retain(|&x| x > 2);
v.clear(); // Svuota il vettore
}
Iterare
let v = vec![1, 2, 3];
// Riferimento immutabile
for val in &v {
println!("{}", val);
}
// Riferimento mutabile
let mut v = vec![1, 2, 3];
for val in &mut v {
*val *= 2;
}
println!("{:?}", v); // [2, 4, 6]
// Consumo (prende ownership)
for val in v {
println!("{}", val);
}
// v non è più utilizzabile qui
Ordinamento
fn main() {
let mut numeri = vec![3, 1, 4, 1, 5, 9];
numeri.sort(); // [1, 1, 3, 4, 5, 9]
numeri.sort_by(|a, b| b.cmp(a)); // [9, 5, 4, 3, 1, 1] (decrescente)
// Ordinamento per float
let mut decimali = vec![3.1, 1.5, 2.7];
decimali.sort_by(|a, b| a.partial_cmp(b).unwrap());
}
Metodi Utili
fn main() {
let v = vec![1, 2, 3, 2, 4, 2, 5];
println!("{}", v.len()); // 7
println!("{}", v.is_empty()); // false
println!("{}", v.contains(&3)); // true
// Deduplicare (richiede ordinamento)
let mut v2 = vec![1, 1, 2, 2, 3];
v2.dedup();
println!("{:?}", v2); // [1, 2, 3]
// Slice da un vettore
let porzione = &v[1..4]; // [2, 3, 2]
// Concatenare vettori
let a = vec![1, 2];
let b = vec![3, 4];
let c = [a, b].concat(); // [1, 2, 3, 4]
}
Capacità e Performance
fn main() {
let mut v = Vec::with_capacity(10);
println!("Len: {}, Cap: {}", v.len(), v.capacity()); // 0, 10
for i in 0..10 {
v.push(i); // Nessuna riallocazione
}
v.push(10); // Qui avviene una riallocazione
v.shrink_to_fit(); // Riduce la capacità alla lunghezza
}
Trasformazioni con Iteratori
let numeri = vec![1, 2, 3, 4, 5];
let doppi: Vec<i32> = numeri.iter().map(|x| x * 2).collect();
let pari: Vec<&i32> = numeri.iter().filter(|x| *x % 2 == 0).collect();
let somma: i32 = numeri.iter().sum();
println!("{:?}", doppi); // [2, 4, 6, 8, 10]
println!("{:?}", pari); // [2, 4]
println!("{}", somma); // 15
Conclusione
Vec<T> è la collezione più versatile in Rust, ideale per liste di dimensione variabile. Pre-allocare la capacità con Vec::with_capacity migliora le performance quando la dimensione approssimativa è nota. Combinato con gli iteratori, Vec offre un modo potente e idiomatico per manipolare collezioni di dati.