In this lesson, you will learn how to manipulate continuous data flows using asynchronous functional operators like map and fold.
When working with asynchronous streams—where data arrives over time—you often need to transform the incoming values without waiting for the entire sequence to complete. Just like standard iterators, asynchronous streams allow you to process elements as they arrive, maintaining non-blocking performance.
Mapping Asynchronous Data
The map operator is the most common way to transform a stream. When you apply map to an async stream, you are essentially defining a transformation function that runs every time a new item is emitted.
use futures::stream::{self, StreamExt};
let numbers = stream::iter(vec![1, 2, 3]);
let squared = numbers.map(|x| x * x);
// squared is a new stream that yields 1, 4, 9 asynchronously
This is powerful because the transformation is deferred; the logic inside map only executes when the consumer actually pulls the next item from the stream.
Folding Streams
While map transforms items one-by-one, fold allows you to aggregate a stream into a single asynchronous result. This is useful for tasks like calculating the sum of a telemetry stream or aggregating bytes into a structured buffer. Because fold must process every element to arrive at a final state, it returns a Future that resolves once the stream is exhausted.
let numbers = stream::iter(vec![1, 2, 3]);
let sum = numbers.fold(0, |acc, x| async move { acc + x }).await;
// sum is 6
Why This Matters
By chaining these operators, you build a declarative "pipeline." Instead of manually managing loops or complex state machines, you define the intent of your data flow. Because these operations are lazy, your system remains responsive, only consuming CPU cycles when there is actual work to be performed by the executor. Whether you are filtering network packets or computing running totals, functional transformations keep your async logic clean and modular.
Key Takeaway: Async stream transformations like map and fold allow you to declaratively process data flows while keeping your code non-blocking and memory efficient.