Ce face Iterator::peekable
Un iterator obișnuit nu îți arată ce urmează fără să-l scoată. peekable() îl învelește într-un Peekable, care are metoda peek(): returnează Option<&Item> cu următorul element, iar acesta rămâne disponibil pentru următorul next().
Este baza analizei de text pas cu pas (un „tokenizer”): citești un caracter, te uiți la următorul ca să decizi dacă numărul continuă, cuvântul se termină etc. next_if(|x| cond) consumă următorul element doar dacă îndeplinește condiția, iar next_if_eq(&v) doar dacă e egal cu v.
peek cere &mut self (poate fi nevoie să citească din sursă), deci iteratorul trebuie declarat mut.
Ce returnează
peekable() returnează un Peekable<Self>. peek() returnează Option<&Item>.
Exemple
Exemplul 1: peek nu consumă
fn main() {
let mut it = ["Ana", "Mihai", "Ioana"].iter().peekable();
println!("peek: {:?}", it.peek());
println!("peek din nou: {:?}", it.peek());
println!("next: {:?}", it.next());
while let Some(nume) = it.next() {
if it.peek().is_some() {
print!("{nume}, ");
} else {
println!("{nume}.");
}
}
}
Rezultat
peek: Some("Ana")
peek din nou: Some("Ana")
next: Some("Ana")
Mihai, Ioana.
Exemplul 2: Împărțirea unei expresii în numere și operatori
După o cifră, next_if mai ia cifre cât timp urmează cifre, ca „12” să fie un singur număr.
fn main() {
let expresie = "12+7*305-4";
let mut it = expresie.chars().peekable();
let mut bucati = Vec::new();
while let Some(c) = it.next() {
if c.is_ascii_digit() {
let mut numar = c.to_string();
while let Some(cifra) = it.next_if(|x| x.is_ascii_digit()) {
numar.push(cifra);
}
bucati.push(numar);
} else {
bucati.push(c.to_string());
}
}
println!("{:?}", bucati);
}
Rezultat
["12", "+", "7", "*", "305", "-", "4"]
Exemplul 3: Grupuri de valori consecutive egale
Comprimăm „aaabccdddd” în perechi (literă, de câte ori apare la rând).
fn main() {
let text = "aaabccdddd";
let mut it = text.chars().peekable();
let mut grupuri = Vec::new();
while let Some(c) = it.next() {
let mut n = 1;
while it.next_if_eq(&c).is_some() {
n += 1;
}
grupuri.push((c, n));
}
println!("{:?}", grupuri);
let comprimat: String = grupuri.iter().map(|(c, n)| format!("{n}{c}")).collect();
println!("{comprimat}");
}
Rezultat
[('a', 3), ('b', 1), ('c', 2), ('d', 4)]
3a1b2c4d
Greșeli frecvente
- Declari
let it = v.iter().peekable();fărămut: cannot borrow `it` as mutable.peekare nevoie de&mut. - Ții referința de la
peek()și apoi apelezinext(): conflict de împrumut. Copiază valoarea (it.peek().copied()) sau compar-o imediat. - Folosești
take_whilepentru a citi un prefix și pierzi elementul care a oprit condiția. Cupeekable+next_if, acel element rămâne în iterator.
Comenzi înrudite
Iterator: Trait-ul care descrie orice șir de valori produse pe rând: next() dă următoarea valoare, sau None la final.Iterator::take_while: take_while dă elemente cât timp condiția e adevărată și se oprește la primul care nu o îndeplinește; skip_while sare până atunci.Iterator::by_ref: Împrumută iteratorul în loc să-l consume, ca să poți folosi un adaptor pe o parte din el și să continui apoi cu restul.iter::from_fn: Creează un iterator dintr-un closure: fiecare apel al closure-ului dă următorul element, iar None oprește iteratorul.