0

I have a data structure called VecCircular and for a non-consuming immutable implementation of std::iter::Iterator, I followed the guidelines here. here is my code:

pub struct VecCircularIterator<'a, T> {
    vec_circular: &'a VecCircular<T>,
    index: usize,
}

impl<'a, T> std::iter::IntoIterator for &'a VecCircular<T> {
    type Item = &'a T;
    type IntoIter = VecCircularIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        VecCircularIterator {
            vec_circular: &self,
            index: self.front_index,
        }
    }
}

impl<'a, T> std::iter::Iterator for VecCircularIterator<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        if self.index == self.vec_circular.rear_index || self.vec_circular.empty() {
            return None;
        } else {
            let item = &self.vec_circular[self.index];
            self.index = (self.index + 1) % self.vec_circular.capacity;
            return Some(item);
        }
    }
}

but when I try to change that implementation to a mutable one:

pub struct VecCircularIterator<'a, T> {
    vec_circular: &'a mut VecCircular<T>,
    index: usize,
}

impl<'a, T> std::iter::IntoIterator for &'a VecCircular<T> {
    type Item = &'a T;
    type IntoIter = VecCircularIterator<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        VecCircularIterator {
            vec_circular: &mut self,
            index: self.front_index,
        }
    }
}

impl<'a, T> std::iter::Iterator for VecCircularIterator<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        if self.index == self.vec_circular.rear_index || self.vec_circular.empty() {
            return None;
        } else {
            let item = &self.vec_circular[self.index];
            self.index = (self.index + 1) % self.vec_circular.capacity;
            return Some(item);
        }
    }
}

I get the following error:

    error[E0495]: cannot infer an appropriate lifetime for lifetime parameter in function call due to conflicting requirements
   --> src/queue/mod.rs:143:25
    |
143 |             let item = &self.vec_circular[self.index];
    |                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    |
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 139:5...
   --> src/queue/mod.rs:139:5
    |
139 | /     fn next(&mut self) -> Option<&'a T> {
140 | |         if self.index == self.vec_circular.rear_index || self.vec_circular.empty() {
141 | |             return None;
142 | |         } else {
...   |
146 | |         }
147 | |     }
    | |_____^
note: ...so that reference does not outlive borrowed content
   --> src/queue/mod.rs:143:25
    |
143 |             let item = &self.vec_circular[self.index];
    |                         ^^^^^^^^^^^^^^^^^
note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 137:6...
   --> src/queue/mod.rs:137:6
    |
137 | impl<'a, T> std::iter::Iterator for VecCircularIterator<'a, T> {
    |      ^^
note: ...so that the types are compatible
   --> src/queue/mod.rs:139:41
    |
139 |       fn next(&mut self) -> Option<&'a T> {
    |  _________________________________________^
140 | |         if self.index == self.vec_circular.rear_index || self.vec_circular.empty() {
141 | |             return None;
142 | |         } else {
...   |
146 | |         }
147 | |     }
    | |_____^
    = note: expected  `std::option::Option<&'a T>`
               found  `std::option::Option<&T>`

error: aborting due to previous error

For more information about this error, try `rustc --explain E0495`.
error: could not compile `rudac`.

I'm a little shaky on rust lifetime parameters and I can't figure out what to do here.

Amin Rayej
  • 21
  • 4
  • Another good question to look through is [How can I create my own data structure with an iterator that returns mutable references?](https://stackoverflow.com/questions/25730586/how-can-i-create-my-own-data-structure-with-an-iterator-that-returns-mutable-ref) – SCappella Apr 21 '20 at 22:23

1 Answers1

0

An Iterator cannot yield borrowed values from within itself. The API declaration for next would otherwise have to tie the Self::Item with a lifetime to self.

You could yield the value instead of a reference e.g., something like this (but your code example is incomplete (missing VecCircular) so it's hard to guess what's a good way to do it):

impl<T> std::iter::Iterator for VecCircularIterator<T> {
    type Item = T;
    fn next(&mut self) -> Option<T> {
        if self.index == self.vec_circular.rear_index || self.vec_circular.empty() {
            return None;
        } else {
            let item = self.vec_circular[self.index];
            self.index = (self.index + 1) % self.vec_circular.capacity;
            return item;
        }
    }
}

Also note that there is a problem with your into_iter method. into_iter consumes self so if you assign a reference to vec_circular it will not live long enough (it goes out of scope once into_iter returns).

Btw. since it looks like you are implementing a queue on your own, you may also be interested in VecDeque from the standard library. It also provides Iter, which can yield references. It does that by not owning the VecDeque itself and instead just borrows a slice from it.

zgerd
  • 1,080
  • 8
  • 17