In Rust is de hele standaard collectie bibliotheek gebaseerd op het concept van iterators. Een iterator is een object dat de trait Iterator implementeert, waarin de methode next() is gedefinieerd. Deze methode retourneert het volgende element van de gegevensreeks (Option<T>, waarbij Some(T) de volgende waarde is en None het einde van de reeks).
Voorbeeld van een standaard iterator:
let v = vec![1, 2, 3]; let mut iter = v.iter(); while let Some(x) = iter.next() { println!("{}", x); }
Iterator-adapters zijn methoden (zoals .map(), .filter(), .enumerate(), .take()) die nieuwe iterators retourneren die de waarden "on-the-fly" verwerken volgens de doorgegeven functies.
Aangepaste iterators worden geïmplementeerd door een structuur te creëren en de trait Iterator met eigen gedrag te implementeren:
struct Counter { count: u8 } impl Iterator for Counter { type Item = u8; fn next(&mut self) -> Option<Self::Item> { if self.count < 5 { self.count += 1; Some(self.count) } else { None } } }
Gebruik standaard adapters wanneer ze voldoende zijn voor het verwerken van collecties. Het is nodig een eigen iterator te implementeren als:
Is het mogelijk om oneindige iterators te creëren? Wat gebeurt er als je probeert ze te verzamelen in een collectie, bijvoorbeeld met
.collect()?
Antwoord: Ja, in Rust zijn er iterators zoals std::iter::repeat, die een oneindige reeks retourneren:
let mut endless = std::iter::repeat(1); endless.next(); // zal steeds Some(1) retourneren
Als je probeert zo'n iterator te verzamelen in een collectie via .collect(), zal de applicatie vastlopen of crasht door geheugenoverloop, omdat de iteratie zichzelf niet zal beëindigen!
Verhaal
In een REST API-project werd een array van 1000 elementen gesorteerd en vervolgens werd .iter().filter(|x| *x > 500) gebruikt, maar in plaats van .collect::<Vec<_>>() werd .fold(0, |acc, _| acc + 1) binnen een complexe adapter toegepast, waarbij het begrip over het juiste eind van de iteratie verloren ging. Resultaat: willekeurige vastlopers door filtering op een onbeperkte luiheid van de iterator met een interne fout.
Verhaal
In een op maat gemaakte engine voor het genereren van unieke id's besloot een willekeurige ontwikkelaar om zijn eigen iterator te implementeren, maar vergat None te retourneren bij het bereiken van de limiet. Als resultaat ging de iteratie in een oneindige lus, de server in productie verbruikte alle CPU en reageerde niet op verzoeken.
Verhaal
In het frontend-gedeelte (WebAssembly-module) gebruikten ze een iterator met geneste adapters: .map().filter().skip(), en probeerden het resultaat te krijgen via .collect() voor een formulier. Bij het wijzigen van het type onder de adapter gaf Rust een complexe compileertijdfout over type-mismatch, omdat ze vergaten het exacte type van de collectie aan te geven: .collect::<Vec<_>>(). Het probleem werd opgelost door de annotatie toe te voegen, maar ze verloren enkele uren aan het zoeken naar de oorzaak.