yymmyb
yymmyb

Reputation: 104

How to shorten the lifetime of each item in IntoIterator?

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

Answers (1)

Chayim Friedman
Chayim Friedman

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

Related Questions