# Iterators and closures

Follow iterator items, closure captures, and errors through your code.

Canonical: https://rust.robertdevore.com/course/11-iterators/
Author: Robert DeVore
Technical baseline: Rust 1.98.1, edition 2024; verified 2026-09-06.

## An iterator describes a sequence of steps

An iterator produces an `Option<Item>` each time `next` is called. Many adaptors, including `map` and `filter`, are lazy: constructing them does not perform the whole computation. A consumer such as `collect`, `sum`, or a `for` loop drives the steps.


### Run the example

```sh
cargo run --locked --example 11_iterators
```

```rust
fn main() {
    let rows = ["INFO a", "WARN b", "WARN c"];
    let warnings: Vec<_> = rows
        .iter()
        .copied()
        .filter(|row| row.starts_with("WARN "))
        .collect();
    assert_eq!(warnings, ["WARN b", "WARN c"]);
    let parsed: Result<Vec<_>, _> = rows.iter().map(|row| audit_core::parse(row)).collect();
    assert_eq!(parsed.unwrap().len(), 3);
}
```

[View the tested source](https://github.com/robertdevore/rust.robertdevore.com/blob/main/examples/11_iterators.rs)


`rows.iter()` yields references to array elements, so each item is `&&str`. `copied()` copies the small shared reference to give `&str`; it does not duplicate the text allocation. `filter` itself passes a reference to its item to the predicate. Check the item type at each step so you know which references to dereference.

Collecting an iterator of `Result` values into `Result<Vec<_>, _>` stops at the first error. This chooses to stop on the first failure. Collecting all errors requires a different design and often a different output type. A concise iterator chain is good only when its policy remains clear.

## Closures capture what they need

A closure is an anonymous function-like value that can capture its environment. It may borrow shared data, borrow it mutably, or consume captured values depending on its body. `move` requests ownership capture; it does not by itself imply the closure can only be called once. The operations performed by the body determine whether it implements `Fn`, `FnMut`, or only `FnOnce`.

A closure that consumes a captured string by returning it can generally run only once. A closure that owns a string but only reads its length can run repeatedly. This distinction matters when passing closures to iterators and spawning tasks.

## Prefer understandable data flow

A loop is often clearer when you must update several counters, attach a line number to an error, and maintain a record-size limit. Use whichever is easier to follow. Both can compile efficiently; measure before claiming one is faster.

Avoid collecting merely to iterate immediately again when a streaming consumer would do. Conversely, collecting is sensible when you need random access or multiple passes. If a borrow makes the chain difficult to write, check who needs to own the data before cloning the collection.

## Exercise

Change the fixture to include `BOGUS bad` between two valid records. Show that collecting into `Result<Vec<_>, _>` returns the parser error. Then implement an explicit loop that counts valid records and errors separately, and write down how that changes the tool's contract.

<details><summary>Solution and acceptance check</summary>

The first version returns `UnknownLevel`, with no successful vector. The second can retain two valid records and one rejection count. Report the rejected record too, so users know the counts are incomplete. Use a `match` on each result to make that policy visible.

</details>

Sources: [`Iterator`](https://doc.rust-lang.org/std/iter/trait.Iterator.html), [closure capture](https://doc.rust-lang.org/reference/types/closure.html), and [`FromIterator` for `Result`](https://doc.rust-lang.org/std/result/enum.Result.html#impl-FromIterator%3CResult%3CA,+E%3E%3E-for-Result%3CV,+E%3E).

