The following is the code:
struct A;
fn f<'a, I>(default_args: I)
where
I: IntoIterator<Item = &'a A>,
{
{
let a1 = A;
let more_args = [&a1];
{
let i = default_args.into_iter();
let i = i.chain(more_args);
// I will use `i` here.
}
}
// I will NOT use `*_args` here.
}
The following is error:
error[E0597]: `a1` does not live long enough
--> src\main.rs:27:26
|
21 | fn f<'a, I>(default_args: I)
| -- lifetime `'a` defined here
...
27 | let more_args = [&a1];
| ^^^ borrowed value does not live long enough
...
30 | let i = i.chain(more_args);
| ------------------ argument requires that `a1` is borrowed for `'a`
...
33 | }
| - `a1` dropped here while still borrowed
For more information about this error, try `rustc --explain E0597`.
I want to get a new default_args_2 from default_args, where the Item inside default_args_2 has a shorter lifetime, as long as it valid inside the function.
>Solution :
You can add a little (almost) noop .map(|v| v):
let i = default_args.into_iter().map(|v| v);
The problem was that the iterator item types have to match, and therefore the chained iterator has to also yield &'a T, which it does not (it yields a shorter lifetime).
Since you don’t really need to use the items for 'a, the trick of the noop map() is to insert a subtyping point: Now, the closure inside map() (conceptually) converts the &'a T, to a &'shorter_lifetime T, which is fine since 'a: 'shorter_lifetime, but now the chained iterator can produce the desired item type.
Putting it differently, you cannot convert impl Iterator<Item = &'a T> into impl Iterator<Item = &'shorter_lifetime T> (as it may not be covariant over the lifetime), but you can convert &'a T to &'shorter_lifetime T, and we use that fact because from the outside we have impl Iterator<Item = &'a T>, but inside map()‘s closure we got &'a T.