00
:
00
:
00
:
00
Corso SEO AI - Usa SEOEMAIL al checkout per il 30% di sconto

Iteratori in Rust

Gli iteratori in Rust sono un pattern fondamentale per elaborare sequenze di elementi in modo lazy (pigro) e con zero overhead grazie alle ottimizzazioni del compilatore.

Il Trait Iterator

pub trait Iterator {
    type Item;
    fn next(&mut self) -> Option<Self::Item>;
}

Ogni iteratore implementa next(), che restituisce Some(valore) o None quando la sequenza è terminata.

Creare Iteratori da Collezioni

let v = vec![1, 2, 3];

// iter() - riferimenti immutabili (&T)
for val in v.iter() {
    println!("{}", val);
}

// iter_mut() - riferimenti mutabili (&mut T)
let mut v = vec![1, 2, 3];
for val in v.iter_mut() {
    *val *= 2;
}

// into_iter() - prende ownership (T)
for val in v.into_iter() {
    println!("{}", val);
}
// v non è più utilizzabile

Adattatori (Lazy)

Gli adattatori trasformano un iteratore in un altro senza eseguire nulla fino al consumo:

let numeri = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

// map - trasforma ogni elemento
let doppi: Vec<i32> = numeri.iter().map(|x| x * 2).collect();

// filter - seleziona elementi
let pari: Vec<&i32> = numeri.iter().filter(|x| *x % 2 == 0).collect();

// flat_map - mappa e appiattisce
let parole: Vec<&str> = vec!["ciao mondo", "hello world"]
    .iter()
    .flat_map(|s| s.split_whitespace())
    .collect();

// enumerate - aggiunge indice
for (i, val) in numeri.iter().enumerate() {
    println!("{}: {}", i, val);
}

// zip - combina due iteratori
let nomi = vec!["Alice", "Bob"];
let eta = vec![25, 30];
let persone: Vec<_> = nomi.iter().zip(eta.iter()).collect();

// take e skip
let primi_tre: Vec<&i32> = numeri.iter().take(3).collect();
let senza_primi: Vec<&i32> = numeri.iter().skip(3).collect();

// chain - concatena iteratori
let tutti: Vec<i32> = (1..4).chain(7..10).collect();
// [1, 2, 3, 7, 8, 9]

Consumatori

I consumatori eseguono l’iteratore e producono un risultato:

let numeri = vec![1, 2, 3, 4, 5];

let somma: i32 = numeri.iter().sum();           // 15
let conteggio = numeri.iter().count();           // 5
let minimo = numeri.iter().min();                // Some(1)
let massimo = numeri.iter().max();               // Some(5)

// fold - riduzione personalizzata
let prodotto = numeri.iter().fold(1, |acc, x| acc * x); // 120

// any e all
let ha_pari = numeri.iter().any(|x| x % 2 == 0);   // true
let tutti_positivi = numeri.iter().all(|x| *x > 0); // true

// find e position
let primo_pari = numeri.iter().find(|x| *x % 2 == 0); // Some(2)
let pos = numeri.iter().position(|x| *x == 3);         // Some(2)

// for_each
numeri.iter().for_each(|x| println!("{}", x));

// collect in diversi contenitori
let set: std::collections::HashSet<_> = numeri.iter().collect();
let stringa: String = ['a', 'b', 'c'].iter().collect();

Iteratore Personalizzato

struct Contatore {
    valore: u32,
    massimo: u32,
}

impl Contatore {
    fn new(massimo: u32) -> Self {
        Contatore { valore: 0, massimo }
    }
}

impl Iterator for Contatore {
    type Item = u32;

    fn next(&mut self) -> Option<Self::Item> {
        if self.valore < self.massimo {
            self.valore += 1;
            Some(self.valore)
        } else {
            None
        }
    }
}

fn main() {
    let somma: u32 = Contatore::new(5)
        .zip(Contatore::new(5).skip(1))
        .map(|(a, b)| a * b)
        .filter(|x| x % 3 == 0)
        .sum();

    println!("{}", somma); // 18
}

Lazy Evaluation

Gli adattatori non fanno nulla finché un consumatore non li attiva:

let v = vec![1, 2, 3];

// Questo NON stampa nulla (lazy)
v.iter().map(|x| {
    println!("{}", x);
    x * 2
});

// Questo SÌ (collect consuma l'iteratore)
let risultato: Vec<_> = v.iter().map(|x| x * 2).collect();

Conclusione

Gli iteratori sono il modo idiomatico in Rust per elaborare sequenze di dati. Grazie alla lazy evaluation e alla monomorfizzazione, le catene di iteratori sono ottimizzate dal compilatore allo stesso livello dei cicli scritti a mano. Preferisci gli iteratori ai cicli for manuali per codice più leggibile, componibile e performante.