How to accept a generic collection that works with both `for a in &coll` AND `for a in coll`


This is for hobby/learning purposes. I’m trying to roll my own implementation of a Centered Interval Tree – I wanted to make a From<C> for my IntervalTree struct, where C is some generic "iterable" collection.

In order to do that, I have two main steps:

  1. Do for a in &coll to compute the "center"
  2. Do a for a in coll to consume the collection and build the tree

It seems like I need two type bounds for the C:

C: IntoIterator<Item = A>,
&C: IntoIterator<Item = &A>

After following advice from the compiler, I’ve got lifetime bounds littered all over the place and have arrived at an error I don’t understand how to resolve:

fn iter_twice<'a, C: 'a, A: 'a>(coll: C)
    where &'a C : IntoIterator<Item = &'a A>,
    C: IntoIterator<Item = A>
    for a in &coll {
        // ...

    for a in coll {
        // ...

error[E0597]: `coll` does not live long enough
  --> src\
53 | fn iter_twice<'a, C: 'a, A: 'a>(coll: C)
   |               -- lifetime `'a` defined here
57 |     for a in &coll {
   |              ^^^^^
   |              |
   |              borrowed value does not live long enough
   |              argument requires that `coll` is borrowed for `'a`
66 | }
   | - `coll` dropped here while still borrowed

I could make my life easier by just accepting Vec<A>, but since this is "just for fun" I figured I’d try to make things work with type-generics.

>Solution :

Because you used a generic lifetime, the caller needs to choose it. But the lifetime the caller will choose does not necessarily match the lifetime of coll (in fact, it can never match it), and this is the error.

What you want is Higher-Ranked Trait Bounds, meaning Iterator is implemented for every lifetime:

fn iter_twice<C, A>(coll: C)
    for<'a> &'a C: IntoIterator<Item = &'a A>,
    C: IntoIterator<Item = A>,
    // ...

Leave a Reply Cancel reply