3

I'm trying to build an iterator that yields a reference to a Vec. I'll try to explain my rationale to understand where my flaw is.

My first attempt was to have the iterator own the object:

pub struct VecIter<T> {
    x: Vec<T>,
}

However, according to Iterator returning items by reference, lifetime issue, this would not work. There were two suggestions in the above answer: don't return a reference, or have a reference to the object.

Quoting from the answer:

For your specific, presumably simple example, you should either stop yielding references, or alter it so that your iterator object does not contain the data that you are iterating over—let it merely contain a reference to it, e.g. &'a [T] or even something like Items<'a, T>.

I want to implement the second option: i.e, return a reference by having the iterator contain a reference.

I've reduced the code to the simplest version that I cannot make it compile:

pub struct VecIter<'a, T> where T: 'a {
    x: &'a mut Vec<T>,
}

impl<'a, T> VecIter<'a, T> {
    fn next_(&'a mut self) -> Option<&'a Vec<T>> {
        // do something to modify self.x
        Some(self.x)
    }
}

pub fn main() {
    let mut vec_i = VecIter{x: &mut vec![100,200,300]};
    while let Some(x) = vec_i.next_() {
        // ...
    }
}

I would expect the above code to work because each mutable borrow only lives inside the loop body. So the idea is to borrow the reference for the body of the loop, use it inside the loop, and end the borrow at the end of the loop.

Is it possible to build such an iterator? i.e., build an iterator that yields a reference to an object that it modifies in next()?

EDIT:

In a comment by Matthieu M, it was suggested that for this to work I should:

remove the 'a so next_(&'a mut self) becomes next_(&mut self)

Maybe I'm understanding something wrong, but I tried this and I got the following compile error. To avoid any confusion here's the code that I tried (playground):

<anon>:8:14: 8:20 error: cannot infer an appropriate lifetime for automatic coercion due to conflicting requirements [E0495]
<anon>:8         Some(self.x)
                      ^~~~~~
<anon>:6:5: 9:6 help: consider using an explicit lifetime parameter as shown: fn next_(&'a mut self) -> Option<&'a Vec<T>>
<anon>:6     fn next_(&mut self) -> Option<&'a Vec<T>> {
<anon>:7         // do something to modify self.x
<anon>:8         Some(self.x)
<anon>:9     }
error: aborting due to previous error
playpen: application terminated with error code 101
Community
  • 1
  • 1
ynimous
  • 4,642
  • 6
  • 27
  • 43
  • 1
    Possible duplicate of [Iterator returning items by reference, lifetime issue](http://stackoverflow.com/questions/24574741/iterator-returning-items-by-reference-lifetime-issue) – DK. Feb 14 '16 at 13:46
  • It's certainly relevant (I'm already mentioning it above) but I do not think it's a duplicate since it suggests using a reference, but does not describe **how** to do it. – ynimous Feb 14 '16 at 13:58
  • @ynimous: A lack of clarity in the answer does not make it "not an answer" (you can of course comment on the answer asking for clarification). In your case, as mentioned by Chris Morgan: remove the `'a` so `next_(&'a mut self)` becomes `next_(&mut self)` => by reusing `'a` you are unintentionally tying up the lifetime of the iterator itself to that of the collection iterated over which is your mistake. – Matthieu M. Feb 14 '16 at 15:25
  • @Mathhieu M. please see EDIT 2. Also I'm not sure where your quote "not an answer" comes from. I never said that, it's just that it's not exactly the same question. – ynimous Feb 14 '16 at 15:41

1 Answers1

1

Here's a modification of your next_() method that seems to work:

fn next_<'b>(&'b mut self) -> Option<&'b Vec<T>>
where 'a: 'b { ... }

The 'b parameter will be elided (lifetime elision), so this will work just as well:

fn next_(&mut self) -> Option<&Vec<T>> { ... }

The lifetimes of self and of self.x are different. I'm having some trouble figuring out the precise reason this doesn't work, but in general, you don't need to write &'x self, and if you ever do, 'x is never a parameter on the type of self.

EDIT: Ok, I get it now. I kept overlooking the fact that self.x is a mutable borrow of a Vec, but you're trying to return an immutable reference to it. If self.x were not marked mut, you could just return Some(self.x) and it would be copied. But you can't copy a mutable reference, so it has to be reborrowed. Furthermore, the existence of a reborrowed (immutable) reference would make it impossible to call &mut self methods or destroy self until the reference was destroyed, so self has to outlast the new borrow. That's why you can't return &'a Vec<T>: if you could, it would become impossible to destroy self.

trent
  • 25,033
  • 7
  • 51
  • 90