Iterators
filter_map()
The .filter_map() adapter combines filtering and mapping into a single step by applying an FnMut(Self::Item) -> Option<B> closure to each element, unwrapping and yielding b for every Some(b) and discarding every None.
Signature
fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
where
Self: Sized,
F: FnMut(Self::Item) -> Option<B>,
Source: [ "42", "bad", "108" ]
│ │ │ .filter_map(|s| s.parse::<i32>().ok())
▼ ▼ ▼
Option: Some(42) None Some(108)
│ ✕ │
▼ ▼
Output: [ 42, 108 ]
Parsing and Extracting Valid Items with .filter_map()
Whenever a transformation naturally returns an Option<B> (or a Result<B, E> converted via .ok()), .filter_map() avoids either parsing twice (.filter(|s| s.parse().is_ok()).map(|s| s.parse().unwrap())) or chaining .map(...).filter(Option::is_some).map(Option::unwrap):
fn main() {
let raw_inputs = ["25", "N/A", "100", "", "-7", "invalid"];
let numbers: Vec<i32> = raw_inputs
.into_iter()
.filter_map(|s| s.parse::<i32>().ok())
.collect();
println!("Parsed integers: {numbers:?}");
}
Parsed integers: [25, 100, -7]
Pattern Matching Inside .filter_map()
.filter_map() is also ideal for extracting a specific enum variant from a heterogeneous sequence:
#[derive(Debug)]
enum Event {
Heartbeat,
Message { sender: &'static str, body: &'static str },
Disconnect,
}
fn main() {
let stream = [
Event::Heartbeat,
Event::Message { sender: "alice", body: "hello" },
Event::Disconnect,
Event::Message { sender: "bob", body: "ack" },
];
let chat_lines: Vec<String> = stream
.iter()
.filter_map(|event| match event {
Event::Message { sender, body } => Some(format!("{sender}: {body}")),
_ => None,
})
.collect();
println!("{chat_lines:?}");
}
["alice: hello", "bob: ack"]
.filter_map(f) vs. .filter(p).map(m)
| Scenario | Prefer |
|---|---|
Condition and transformation are intertwined (e.g., str::parse, checked_add, enum variant extraction) |
.filter_map(f) |
Simple boolean check followed by an unrelated transformation, where filter rejects most items cheaply before an expensive map |
.filter(p).map(m) |
Iterator already yields Option<T> and you only want to unwrap Some(T) |
.flatten() |