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

Stateful Iterator Transformation

You will be able to maintain internal context within an iterator pipeline using custom state objects.

In this lesson, you will learn how to maintain internal memory within an iterator pipeline to perform transformations that depend on previously encountered elements.

The Problem with Statelessness

Standard iterator methods like map or filter are typically stateless. They look at each item in isolation, which is perfect for simple transformations. However, real-world data often requires context—for example, calculating a running total, detecting a change in sequence, or filtering based on a threshold established by a previous value.

Introducing Stateful Transformations

While we could reach for a for loop with an external mut variable, Rust allows us to encapsulate this logic directly into the iterator pipeline using the scan method.

The scan method accepts an initial "state" object and a closure that receives a mutable reference to that state along with the current item. You can update the state as you iterate, and the closure returns an Option that determines what value—if any—is yielded to the next stage of the pipeline.

fn main() {
    let numbers = vec![1, 2, 3, 4, 5];

    // We use 'scan' to keep track of the cumulative sum as state
    let running_totals = numbers
        .iter()
        .scan(0, |sum, &x| {
            *sum += x;
            Some(*sum)
        })
        .collect::<Vec<_>>();

    println!("{:?}", running_totals); // [1, 3, 6, 10, 15]
}

Why Use scan?

By using scan, you keep your logic functional and composable. Instead of leaking mutable state into the surrounding scope, the state is strictly bound to the lifecycle of the iterator. This keeps your data flow clean and prevents accidental side effects outside the pipeline.

You can store complex structs inside scan as well, allowing you to maintain sophisticated counters or buffers while remaining within the zero-cost abstraction paradigm of Rust's iterators. This pattern is particularly useful when you need to perform state-dependent filtering or windowed calculations without manually managing indices or external flags.

Key Takeaway: Use scan to encapsulate internal state within an iterator pipeline, transforming a series of items based on the context of those that came before.