Как реализовать непотребляющий изменяемый std :: iter :: Iterator для структуры данных - PullRequest
0 голосов
/ 21 апреля 2020

У меня есть структура данных, которая называется VecCircular, и для не потребляющей неизменяемой реализации std :: iter :: Iterator я следовал рекомендациям здесь . вот мой код:

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);
        }
    }
}

, но когда я пытаюсь изменить эту реализацию на изменяемую:

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);
        }
    }
}

, я получаю следующую ошибку:

    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`.

Я немного шатаюсь по параметрам срока службы ржавчины и не могу понять, что здесь делать.

1 Ответ

0 голосов
/ 22 апреля 2020

Итератор не может выдавать заимствованные значения изнутри себя. Объявление API для next в противном случае должно было бы иметь значение t ie Self::Item со временем жизни до self.

. Вы можете получить значение вместо ссылки, например, что-то вроде это (но ваш пример кода неполон (отсутствует VecCircular), поэтому трудно догадаться, какой хороший способ это сделать):

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;
        }
    }
}

Также обратите внимание, что есть проблема с вашим методом into_iter. into_iter потребляет self, поэтому, если вы назначите ссылку на vec_circular, она не проживет достаточно долго (она выйдет из области видимости после возврата into_iter).

Кстати. так как похоже, что вы реализуете очередь самостоятельно, вас также может заинтересовать VecDeque из стандартной библиотеки. Он также предоставляет Iter , который может давать ссылки. Это достигается за счет того, что не владеет самой VecDeque , а просто заимствует у нее часть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...