#134 May 12, 2026

134. Iterator::find_map — Find and Transform in One Pass

Looking for the first element that matches and needs to come back as something else? Skip the filter_map(...).next() two-step — find_map says it in one call.

The Problem

You have an iterator and want the first item that satisfies a condition plus the value derived from it. The hand-rolled version is a for loop with a mutable binding and a break:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
let inputs = ["abc", "12", "def", "34"];

let mut first: Option<i32> = None;
for s in &inputs {
    if let Ok(n) = s.parse::<i32>() {
        first = Some(n);
        break;
    }
}
assert_eq!(first, Some(12));

You can compress it with filter_map(...).next():

1
2
3
4
5
let first: Option<i32> = inputs
    .iter()
    .filter_map(|s| s.parse::<i32>().ok())
    .next();
assert_eq!(first, Some(12));

It’s shorter, but what you actually mean — find the first one — is buried inside “filter everything, then take one.”

The Fix: find_map

Iterator::find_map takes a closure returning Option<U> and returns the first Some(U) it produces — short-circuiting as soon as the closure says yes:

1
2
3
4
let first: Option<i32> = inputs
    .iter()
    .find_map(|s| s.parse::<i32>().ok());
assert_eq!(first, Some(12));

Same short-circuit behavior as find, but the closure does the transformation too — no separate map step on the result.

Where It Earns Its Keep

Looking up the first input that’s in a small table:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
fn level(name: &str) -> Option<u8> {
    match name {
        "trace" => Some(0),
        "debug" => Some(1),
        "info"  => Some(2),
        _ => None,
    }
}

let inputs = ["??", "huh", "info", "debug"];
let first = inputs.iter().find_map(|s| level(s));
assert_eq!(first, Some(2));

Pulling the first error out of a batch of Results without losing the message:

1
2
3
4
let results: Vec<Result<i32, &str>> = vec![Ok(1), Ok(2), Err("bad row"), Ok(3)];

let first_err = results.iter().find_map(|r| r.as_ref().err().copied());
assert_eq!(first_err, Some("bad row"));

Anywhere you catch yourself writing .filter_map(...).next() or a manual loop with break, find_map says the same thing with less noise.

← Previous 133. slice::rotate_left — Cycle Elements Through a Slice Without a Second Buffer Next → 135. str::strip_prefix — Trim a Prefix Without Slicing by Hand