The into_iter
method creates an iterator for the vector months
.
The filter
method wraps the iterator with the Filter
iterator adapter. This adapter is an iterator that only returns some of the items returned by the original/wrapped iterator, based on a predicate. Itβs basically a struct
struct Filter<I, P> {
iterator: I,
predicate: P,
}
that implements Iterator
impl<I, P> Iterator for Filter<I, P>
where
I: Iterator,
P: FnMut(&I::Item) -> bool,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
loop {
match self.iterator.next() {
None => return None,
Some(item) if (self.predicate)(&item) => return Some(item),
_ => continue, // Some(item) not matching predicate
}
}
}
}
This could be used directly as follows
fn main() {
let months = vec![
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December",
];
let months_iterator = months.into_iter();
let first_filter = Filter {
iterator: months_iterator,
predicate: |month: &&str| month.len() < 5
};
let second_filter = Filter {
iterator: first_filter,
predicate: |month: &&str| month.contains("u")
};
let filtered_months = second_filter.collect::<Vec<&str>>();
println!("{:?}", filtered_months);
}
(playground)
Or with a helper function
fn filter<I, P>(iterator: I, predicate: P) -> Filter<I, P>
where
I: Iterator,
P: FnMut(&I::Item) -> bool,
{
Filter {
iterator,
predicate,
}
}
[β¦]
let filtered_months = filter(
filter(months.into_iter(), |month| month.len() < 5),
|month| month.contains("u"),
)
.collect::<Vec<&str>>();
The method Iterator::filter
is basically the same as such a helper function, but it supports method-call notation, i.e. iterator.filter(predicate)
instead of filter(iterator, predicate)
.
Finally, collect
walks through this iterator (of type βFilter<Filter<vec::IntoIter<&str>, {closure type β¦}>, {closure type β¦}>
β) and collects all its items into a vector. Writing this manually would look something like
fn collect_vector<I>(mut iterator: I) -> Vec<I::Item>
where
I: Iterator,
{
let mut v = vec![];
while let Some(item) = iterator.next() {
v.push(item);
}
v
}
which could be used as
let filtered_months = collect_vector(filter(
filter(months.into_iter(), |month| month.len() < 5),
|month| month.contains("u"),
));
(playground)