Reputation: 104
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.
Upvotes: 1
Views: 102
Reputation: 71390
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
.
Upvotes: 2