Here's the error for reference:
error[E0623]: lifetime mismatch
--> src/lib.rs:8:42
|
8 | fn filter_s<'a>(&self, s:&String) -> impl Iterator<Item=& String>{
| ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
| | |
| | ...but data from `s` is returned here
| this parameter and the return type are declared with different lifetimes...
Here's why your second function is problematic. The signature of Iterator::filter
looks like this:
pub fn filter<P>(self, predicate: P) -> Filter<Self, P> where
P: FnMut(&Self::Item) -> bool,
The return type is Filter<Self, P>
. This is a type that holds your original iterator (self
) in one field and the predicate/filtering function in another. Filter<Self, P>
is a fully-fledged type: you could assign it to a variable, store it in a struct, etc.
Now, you're passing a closure |i| i == &s
to the filter
. A closure is not quite the same thing as a normal function (the thing you write with the fn
keyword): it can capture local variables from the scope it's written in and carry that data around to use when you eventually call it (potentially more than once). Here, your closure captures the local variable s
. A consequence of this is that the closure can only exist as long as the reference s: &String
is valid.
To see how this causes a compiler error, look again at the type signature you wrote for filter_s
:
fn filter_s<'a>(&self, s: &String) -> impl Iterator<Item = &String>
First of all, you never use the lifetime parameter 'a
, so we can get rid of it.
fn filter_s(&self, s: &String) -> impl Iterator<Item = &String>
Now let's expand all the implicit lifetimes following the elision rules:
fn filter_s<'av, 's>(&'av self, s: &'s String) -> impl Iterator<Item = &'av String> + 'av
(I'm actually not 100% sure how lifetime elision works for impl Trait
in return position; this is my guess based on the compiler's feedback.)
This signature is incompatible with the body you've written for filter_s
, because the returned iterator (Filter<Self, P>
) contains a closure that captures the reference s
, so its lifetime is bounded by 's
, not just by 'av
. A type signature that's compatible with the body of the function is this:
fn filter_s<'b>(&'b self, s: &'b String) -> impl Iterator<Item = &'b String>
That tells the compiler that the same lifetime 'b
governs the borrows self
and s
, so it can use 'b
to bound the lifetime of the returned iterator. You will also need to add the move
keyword in front of the closure so that it captures s
by value instead of by reference.