Option<T> and Result<T, E> in Depth

inspect() and inspect_err()

The .inspect(f) method on Option<T> and Result<T, E>, along with .inspect_err(f) on Result<T, E>, executes a side-effecting closure on a shared reference (&T or &E) to the inner value and returns the original Option or Result unchanged.

Signatures

impl<T> Option<T> {
    pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self;
}

impl<T, E> Result<T, E> {
    pub fn inspect<F: FnOnce(&T)>(self, f: F) -> Self;
    pub fn inspect_err<F: FnOnce(&E)>(self, f: F) -> Self;
}
Method Available On When Closure f Runs Parameter Passed to f Return Value
opt.inspect(f) Option<T> Only when opt is Some(v) &T Original Option<T>
res.inspect(f) Result<T, E> Only when res is Ok(v) &T Original Result<T, E>
res.inspect_err(f) Result<T, E> Only when res is Err(e) &E Original Result<T, E>

Logging and Metrics Inside Combinator or ? Chains

Before .inspect() and .inspect_err() were stabilized, logging an error right before propagating it with ? required writing .map_err(|e| { log(&e); e })?. With .inspect_err(), you can log or record metrics inline without returning e from the closure:

use std::num::ParseIntError;

fn parse_and_scale(raw: &str, factor: i32) -> Result<i32, ParseIntError> {
    let scaled = raw
        .trim()
        .parse::<i32>()
        .inspect(|val| println!("  [debug] parsed raw value: {val}"))
        .inspect_err(|err| println!("  [error] failed to parse '{raw}': {err}"))?
        * factor;

    Ok(scaled)
}

fn main() {
    println!("Result 1: {:?}", parse_and_scale(" 15 ", 4));
    println!("Result 2: {:?}", parse_and_scale("abc", 4));
}
  [debug] parsed raw value: 15
Result 1: Ok(60)
  [error] failed to parse 'abc': invalid digit found in string
Result 2: Err(ParseIntError { kind: InvalidDigit })

Observing Option<T> Pipelines with .inspect()

fn main() {
    let final_tag = Some("  Rust_2024  ")
        .map(str::trim)
        .inspect(|trimmed| println!("After trim: '{trimmed}'"))
        .filter(|s| s.len() >= 5)
        .map(str::to_lowercase);

    println!("Final tag: {final_tag:?}");
}
After trim: 'Rust_2024'
Final tag: Some("rust_2024")