Course contentsShow
← Rust
Lesson 955 of 1,9108. Collections and Iterator PipelinesFree lesson

Lookahead and Peekable Sequences

You will be able to process streams requiring multi-token lookahead without backtracking.

In this lesson, you will learn how to inspect upcoming elements in an iterator stream without consuming them, enabling you to make decisions based on future tokens.

The Problem: Single-Pass Constraints

Standard iterators in Rust are "pull-only." Once you call next(), that element is gone from the stream. This poses a challenge when parsing complex structures, like a mathematical expression where you might need to know if the next character is an operator before deciding how to parse the current character. Without lookahead, you would be forced to buffer items manually or backtrack, both of which are inefficient or complex.

Peekable: The Iterator Observer

Rust provides the Peekable adapter to solve this. By calling .peekable() on any iterator, you create a wrapper that adds a peek() method. Unlike next(), peek() returns an Option<&T>—a reference to the next item—without advancing the iterator’s internal state.

Consider a parser that needs to identify a multi-digit number:

let mut chars = "123+456".chars().peekable();

while let Some(&c) = chars.peek() {
    if c.is_digit(10) {
        // We see a digit, consume it and continue
        println!("Found digit: {}", chars.next().unwrap());
    } else {
        // We see an operator, stop or handle differently
        println!("Found non-digit: {}", chars.next().unwrap());
    }
}

Multi-Token Lookahead

While Peekable only exposes the immediate next item, you can implement multi-token lookahead by keeping a small stateful buffer or by chaining Peekable with other tools like std::iter::from_fn. However, for most stream-processing tasks, "look-one-ahead" is sufficient to resolve ambiguity. By using peek(), you avoid the need for complex backtracking state machines because you decide exactly when to "consume" the lookahead value by calling next() only when you are ready to commit.

This approach maintains the efficiency of lazy evaluation while providing the necessary visibility to handle context-dependent logic in your pipeline.

Key Takeaway: The peekable() adapter allows you to inspect the next element in a sequence without exhausting it, enabling predictive logic within your iterator chains.