filter()
The .filter() adapter tests each element of an iterator with a predicate closure FnMut(&Self::Item) -> bool, yielding only the elements for which the predicate returns true.
Signature and Reference Parameter (&Self::Item)
fn filter<P>(self, predicate: P) -> Filter<Self, P>
where
Self: Sized,
P: FnMut(&Self::Item) -> bool,
Unlike .map(), which passes Self::Item by value, .filter() passes a shared reference (&Self::Item) to the predicate closure. This is necessary because if the predicate returns true, .filter() must still own the original Self::Item to yield it to the next stage of the pipeline:
Source: [ 12, 5, 18, 3 ]
│ │ │ │ .filter(|&x| x >= 10)
▼ ✕ ▼ ✕
Output: [ 12, 18 ]
Reference Layers When Using .filter()
Because .filter() adds one & layer to Self::Item when calling the predicate, the closure parameter type depends on how the iterator was created:
| Iterator Source | Self::Item |
Predicate Parameter (&Self::Item) |
Idiomatic Closure Pattern |
|---|---|---|---|
vec.into_iter() |
T |
&T |
|x| x.is_valid() or |&x| x > 0 (for T: Copy) |
vec.iter() |
&T |
&&T |
|x| x.is_valid() (auto-deref) or |&&x| x > 0 (for T: Copy) |
vec.iter().copied() |
T |
&T |
|&x| x > 0 |
#[derive(Debug)]
struct LogEntry {
status: u16,
path: &'static str,
}
fn main() {
let logs = [
LogEntry { status: 200, path: "/index" },
LogEntry { status: 500, path: "/checkout" },
LogEntry { status: 404, path: "/missing" },
LogEntry { status: 503, path: "/db" },
];
// Field access (`entry.status`) auto-dereferences `&&LogEntry` automatically:
let server_errors: Vec<&LogEntry> = logs
.iter()
.filter(|entry| entry.status >= 500)
.collect();
println!("5xx errors: {server_errors:?}");
}
5xx errors: [LogEntry { status: 500, path: "/checkout" }, LogEntry { status: 503, path: "/db" }]
Effect on size_hint
Because the compiler cannot know ahead of time how many elements will pass the predicate, Filter<I, P> has a size_hint() lower bound of 0 ((0, upper_bound)), and therefore Filter never implements ExactSizeIterator.