Consider a method that accepts a lifetime not related to struct
:
struct Mother<'p> {
kids: Vec<&'p str>,
}
impl<'p> Mother<'p> {
// find kids with similar names defined in `names`
fn search<'n, I, S>(&'p self, names: &'n I) -> Vec<&'p str>
where
&'n I: IntoIterator<Item = S>,
S: AsRef<str>,
{ // `I` is either a vector of `String` or slice of `str`
self.kids
.iter()
.filter( /* use I here */ )
.collect()
}
}
Here lifetime 'n
is defined by caller and search
is enforcing that returned references in Vec
match those of &self
's lifetime (both have 'p
)
My line of thinking is that whenever I call search
, I shouldn't be (manually) concerned about 'n
since the compiler will yell at me if somehow names
is not in scope and dead. And I think this compiling snippet validates (kinda) my thought.
As you can see &names
only lives in runner
function and we are returning a Vec
of references. To come up with those references we have utilized &names
but we are not actually returning them:
fn runner<'p>(mother: &'p Mother) -> Vec<&'p str> {
let names = vec!["kid1", "kid2"];
find_kids(&names, mother) // `names` still in scope while we use it
} // `names` is dropped here, but we are still able to return references from
// this function. seems we don't need `names` anymore!
fn find_kids<'n, 'p, I, S>(names: &'n I, mother: &'p Mother) -> Vec<&'p str>
where
&'n I: IntoIterator<Item = S>,
S: AsRef<str>,
{
mother.search(names)
}
Q1: So can we essentially say that search
"doesn't care" about the lifetime 'n
? even though it uses it to filter stuff?
Which brings me to my non-compiling version of the code. If instead of returning Vec<&'p str>
, we return impl Iterator<Item = &'p str>
then it seems the lifetime 'n
does matter as the compiler is not happy about early death of names
in runner
function.
fn runner<'p>(mother: &'p Mother) -> impl Iterator<Item = &'p str>
{
let names = vec!["kid1", "kid2"];
find_kids(&names, mother)
} // oops, seems `names` is still needed!!! what gives?
fn find_kids<'n, 'p, I, S>(names: &'n I, mother: &'p Mother) -> impl Iterator<Item = &'p str>
where
&'n I: IntoIterator<Item = S>,
S: AsRef<str>,
{
mother.search(names).into_iter()
}
Q2: What makes impl Trait
think it's better than a Vec
of references that it should demand stricter lifetime spans?