Ce face Iterator
Un iterator este un obiect care produce valori una câte una. Singura metodă obligatorie este next(): returnează Some(valoare) cât timp mai sunt valori și None când s-au terminat. Tipul valorilor este Item. Iteratorul își schimbă starea la fiecare apel, de aceea next cere &mut self.
Toate celelalte metode (map, filter, sum, collect și peste 70 de altele) sunt construite peste next, deci orice tip care implementează Iterator le primește gratuit. Bucla for apelează next până la None.
Iteratorii din Rust sunt leneși: v.iter().map(...) nu calculează nimic, ci doar descrie calculul. Valorile sunt produse abia când cineva le cere: o buclă for sau o metodă „consumatoare” precum collect::<Vec<_>>(), sum(), count(). Datorită acestui lucru, lanțurile de adaptoare sunt la fel de rapide ca o buclă scrisă de mână și pot lucra chiar și cu șiruri infinite.
Ce returnează
next() returnează Option<Self::Item>.
Exemple
Exemplul 1: next() apelat de mână
iter() pe un vector produce referințe (&i32). După ultimul element, next returnează None.
fn main() {
let note = vec![9, 7, 10];
let mut it = note.iter();
println!("{:?}", it.next());
println!("{:?}", it.next());
println!("{:?}", it.next());
println!("{:?}", it.next());
}
Rezultat
Some(9)
Some(7)
Some(10)
None
Exemplul 2: Un iterator propriu: numărătoare inversă
Implementăm doar next; sum, filter și collect vin automat din trait.
struct Numaratoare {
ramas: u32,
}
impl Iterator for Numaratoare {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.ramas == 0 {
None
} else {
self.ramas -= 1;
Some(self.ramas + 1)
}
}
}
fn main() {
let lansare = Numaratoare { ramas: 5 };
for n in lansare {
print!("{n} ");
}
println!("start!");
let suma: u32 = Numaratoare { ramas: 10 }.sum();
let pare: Vec<u32> = Numaratoare { ramas: 10 }.filter(|n| n % 2 == 0).collect();
println!("suma 1..10 = {suma}, pare = {:?}", pare);
}
Rezultat
5 4 3 2 1 start!
suma 1..10 = 55, pare = [10, 8, 6, 4, 2]
Exemplul 3: Iteratorii sunt leneși
Crearea lanțului nu afișează nimic. Abia collect cere valorile. În al doilea lanț, find se oprește la primul rezultat, deci 4 nu mai este procesat deloc.
fn main() {
let v = vec![1, 2, 3, 4];
let lant = v.iter().map(|x| {
println!(" procesez {x}");
x * 10
});
println!("lanțul a fost creat, dar nimic nu s-a procesat încă");
let rezultat: Vec<i32> = lant.collect();
println!("rezultat: {:?}", rezultat);
println!("caut primul pătrat mai mare de 5:");
let gasit = v
.iter()
.map(|x| {
println!(" calculez {x}²");
x * x
})
.find(|&p| p > 5);
println!("găsit: {:?}", gasit);
}
Rezultat
lanțul a fost creat, dar nimic nu s-a procesat încă
procesez 1
procesez 2
procesez 3
procesez 4
rezultat: [10, 20, 30, 40]
caut primul pătrat mai mare de 5:
calculez 1²
calculez 2²
calculez 3²
găsit: Some(9)
Greșeli frecvente
- Construiești un lanț (
v.iter().map(...)) și nu îl consumi. Nimic nu se execută, iar compilatorul avertizează: unused `Map` that must be used: iterators are lazy and do nothing unless consumed. Adaugăcollect,for_eachsau o buclăfor. - Declari iteratorul fără
mutși apelezinext(): cannot borrow `it` as mutable.nextmodifică starea iteratorului. - Încerci să parcurgi de două ori același iterator. După prima parcurgere este epuizat și dă doar
None. Creează altul (v.iter()din nou) sau colectează valorile într-un vector.
Comenzi înrudite
IntoIterator: Trait-ul tipurilor care pot fi transformate într-un iterator; este ce folosește bucla for pentru a parcurge o valoare.Iterator::collect: Consumă iteratorul și adună valorile într-o colecție: Vec, String, HashMap, HashSet, chiar Result sau Option.Iterator::map: Transformă fiecare valoare a iteratorului cu o funcție și dă un iterator cu rezultatele; nu calculează nimic până la consumare.Iterator::filter: Păstrează doar elementele pentru care condiția dată returnează true; restul sunt sărite.Vec::iter: Cele trei moduri de a parcurge un vector: iter dă referințe, iter_mut dă referințe mutabile, into_iter dă elementele.DoubleEndedIterator: Iterator care poate produce valori și de la coadă (next_back); permite rev(), rfind() și parcurgerea din ambele capete.