Ce face DoubleEndedIterator
Un DoubleEndedIterator are, pe lângă next(), metoda next_back(), care dă următoarea valoare de la capătul celălalt. Cele două capete se apropie unul de altul și se întâlnesc: fiecare element este produs o singură dată.
Îl implementează iteratorii vectorilor, slice-urilor, intervalelor (0..10), ai lui chars(), BTreeMap și adaptoarele construite peste ei (map, filter, zip pe lungimi egale etc.). Datorită lui funcționează rev(), rfind(), rposition(), nth_back() și last() eficient.
Iteratorii care nu știu unde se termină (iter::from_fn, successors, (1..), citirea liniilor din fișier) nu îl implementează, deci rev() nu compilează pentru ei.
Ce returnează
next_back() returnează Option<Self::Item>.
Exemple
Exemplul 1: Din ambele capete
fn main() {
let mut it = vec!["Ana", "Bogdan", "Cristina", "Dan", "Elena"].into_iter();
println!("{:?}", it.next());
println!("{:?}", it.next_back());
println!("{:?}", it.next());
println!("{:?}", it.next_back());
println!("rămas: {:?}", it.collect::<Vec<_>>());
}
Rezultat
Some("Ana")
Some("Elena")
Some("Bogdan")
Some("Dan")
rămas: ["Cristina"]
Exemplul 2: rfind, nth_back și rposition
fn main() {
let temperaturi = [3, 7, 12, 5, 14, 9, 2];
let ultima_peste_10 = temperaturi.iter().rfind(|&&t| t > 10);
let penultima = temperaturi.iter().nth_back(1);
let poz = temperaturi.iter().rposition(|&t| t < 5);
println!("ultima peste 10: {:?}", ultima_peste_10);
println!("penultima: {:?}", penultima);
println!("ultima sub 5 e pe poziția {:?}", poz);
let litere: String = "Iași".chars().rev().collect();
println!("{litere}");
}
Rezultat
ultima peste 10: Some(14)
penultima: Some(9)
ultima sub 5 e pe poziția Some(6)
ișaI
Exemplul 3: next_back pentru un iterator propriu
Un interval de pagini care poate fi parcurs din ambele capete. Cu next_back implementat, primim gratuit rev().
struct Pagini {
prima: u32,
ultima: u32,
}
impl Iterator for Pagini {
type Item = u32;
fn next(&mut self) -> Option<u32> {
if self.prima > self.ultima {
return None;
}
self.prima += 1;
Some(self.prima - 1)
}
}
impl DoubleEndedIterator for Pagini {
fn next_back(&mut self) -> Option<u32> {
if self.prima > self.ultima {
return None;
}
self.ultima -= 1;
Some(self.ultima + 1)
}
}
fn main() {
let inainte: Vec<u32> = Pagini { prima: 1, ultima: 5 }.collect();
let inapoi: Vec<u32> = Pagini { prima: 1, ultima: 5 }.rev().collect();
println!("{:?} / {:?}", inainte, inapoi);
}
Rezultat
[1, 2, 3, 4, 5] / [5, 4, 3, 2, 1]
Greșeli frecvente
- Apelezi
rev()pe un iterator care nu are capăt cunoscut, de exemplu(1..).rev()sauiter::from_fn(..).rev(): the trait bound `..: DoubleEndedIterator` is not satisfied. Colectează întâi într-un vector. - Crezi că
next_backdupă epuizarea luinextmai dă ceva. Cele două capete împart aceleași elemente; când s-au întâlnit, ambele dauNone.
Comenzi înrudite
Iterator::rev: Inversează direcția unui iterator: produce elementele de la ultimul la primul, fără să copieze nimic.Iterator: Trait-ul care descrie orice șir de valori produse pe rând: next() dă următoarea valoare, sau None la final.Iterator::nth: nth(n) returnează elementul de pe poziția n (de la 0) și îl consumă împreună cu cele dinainte; last returnează ultimul element.Iterator::position: Returnează poziția (indexul de la 0) primului element care îndeplinește condiția, sau None.Vec::reverse: Inversează pe loc ordinea elementelor: primul devine ultimul, ultimul devine primul.