Iterators

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.