#119 May 4, 2026

119. iter::from_fn — Build a Custom Iterator Without the Struct

Need a custom iterator that carries a bit of state? Skip the struct plus impl Iterator boilerplate. iter::from_fn turns any closure that returns Option<T> into a real iterator.

The problem

You want a custom iterator with some captured state — a counter, a parser cursor, a lazy generator. The textbook approach is a struct plus a manual Iterator impl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
struct Counter { n: u32, max: u32 }

impl Iterator for Counter {
    type Item = u32;
    fn next(&mut self) -> Option<u32> {
        if self.n < self.max {
            self.n += 1;
            Some(self.n)
        } else {
            None
        }
    }
}

let counter = Counter { n: 0, max: 5 };
let v: Vec<u32> = counter.collect();
assert_eq!(v, vec![1, 2, 3, 4, 5]);

Three lines of logic, ten lines of scaffolding.

The fix

std::iter::from_fn takes a FnMut() -> Option<T> and returns an iterator. Yield Some(x) for each item, None to stop. The closure’s captured variables become your iterator state:

1
2
3
4
5
6
7
8
use std::iter;

let mut n = 0;
let v: Vec<u32> = iter::from_fn(|| {
    n += 1;
    (n <= 5).then_some(n)
}).collect();
assert_eq!(v, vec![1, 2, 3, 4, 5]);

The closure captures n mutably and updates it on every call. No struct, no impl, no type to name.

Where it shines: tiny tokenizers

from_fn really earns its keep when paired with Peekable::next_if. Pull characters until a condition fails and you have a one-liner tokenizer:

1
2
3
4
5
6
7
8
let mut chars = "123abc".chars().peekable();
let digits: String =
    iter::from_fn(|| chars.next_if(|c| c.is_ascii_digit())).collect();
assert_eq!(digits, "123");

// chars still has "abc" left to consume
let rest: String = chars.collect();
assert_eq!(rest, "abc");

Reach for from_fn whenever the iterator’s state would just be a couple of local variables. Reach for a manual impl Iterator when the iterator is a public type, needs to implement other traits, or you want a size hint and specialization.

← Previous 118. [T; N]::map — Transform an Array Without Allocating a Vec