Iterators
peekable()
The .peekable() adapter wraps an iterator in a std::iter::Peekable<Self> struct that adds one-element lookahead via .peek(), allowing you to inspect the next element by reference (Option<&Self::Item>) without consuming it.
Key Methods on Peekable<I>
| Method | Signature | Behavior |
|---|---|---|
.peek() |
fn peek(&mut self) -> Option<&I::Item> |
Pulls and caches the next item if not already buffered, returning a shared reference to it |
.peek_mut() |
fn peek_mut(&mut self) -> Option<&mut I::Item> |
Returns a mutable reference to the peeked item, allowing in-place modification before .next() |
.next_if(pred) |
fn next_if(&mut self, func: impl FnOnce(&I::Item) -> bool) -> Option<I::Item> |
Consumes and returns the next item only if func(&item) returns true |
.next_if_eq(expected) |
fn next_if_eq<T>(&mut self, expected: &T) -> Option<I::Item> |
Consumes and returns the next item only if it equals expected |
Underlying Iterator: [ 'b', 'c' ]
Peekable Buffer: Some('a') <-- .peek() returns Some(&'a') without advancing
<-- .next() takes Some('a') from buffer
Notice that .peek() takes &mut self even though it returns an immutable reference Option<&I::Item>, because the first call to .peek() must call .next() on the underlying iterator and store the item inside Peekable's internal Option<Option<I::Item>> cache.
Lexing or Grouping Consecutive Runs with .peek() and .next_if_eq()
Peekable is essential in tokenizers, parsers, and run-length encoders where deciding whether to consume the next item depends on what it is:
fn run_length_encode(input: &str) -> Vec<(char, usize)> {
let mut chars = input.chars().peekable();
let mut runs = Vec::new();
while let Some(ch) = chars.next() {
let mut count = 1;
// Consume subsequent identical characters using `next_if_eq`:
while chars.next_if_eq(&ch).is_some() {
count += 1;
}
runs.push((ch, count));
}
runs
}
fn main() {
let encoded = run_length_encode("aaabbcdddd");
println!("{encoded:?}");
}
[('a', 3), ('b', 2), ('c', 1), ('d', 4)]
Inspecting Without Consuming via .peek()
fn main() {
let mut nums = [10, 20, 30].into_iter().peekable();
println!("Peek 1: {:?}", nums.peek());
println!("Peek 2: {:?}", nums.peek()); // Still 10!
println!("Next 1: {:?}", nums.next()); // Consumes 10
println!("Peek 3: {:?}", nums.peek()); // Now 20
}
Peek 1: Some(&10)
Peek 2: Some(&10)
Next 1: Some(10)
Peek 3: Some(&20)