2017-01-22 15 views
2

Я пытаюсь реализовать итератор в своей собственной структуре. Мой общий подход заключается в создании и сохранении итератора при первом вызове next, а затем при вызове этого итератора каждый раз, когда мне нужно значение.Попытка реализовать итератор: не может вывести соответствующий срок службы из-за противоречивых требований.

Мой пример минимальный недостаток looks like this, и сердце его является:

if !self.vals.is_some() { 
     self.vals = Some(Box::new({ 
      self.display.chars().filter(|&i| i == self.look_for) 
     }) as Box<std::iter::Iterator<Item = _>>); 
    } 

Мой код не компилировать, производя следующее сообщение:

help: consider using an explicit lifetime parameter as shown: fn next(self: &'a mut Self) -> Option<<Self>::Item> 

Этот совет не помогает (просто приводит к более компиляционным ошибкам, говорящим о том, что моя реализация несовместима с определением признака Iterator.

Буду признателен за понимание у меня все получится, и как я могу это исправить.

ответ

3

Проблема в том, что закрытие, которое вы проходите до filter, должно занимать self, но you can't store a reference to self in the struct itself.

В этом случае мы можем обойти это, сохранив вместо этого копию значения в закрытии. Это делается в два этапа:

  1. Присвойте self.look_for локальной переменной и вместо этого используйте локальную переменную в закрытии. Таким образом, закрытие не привязано к self.
  2. Добавить move к закрытию. Таким образом, замыкание фиксирует локальную переменную по значению.

Вот окончательный код:

impl<'a> Iterator for StatefulCounter<'a> { 
    type Item = bool; 
    fn next(&mut self) -> Option<Self::Item> { 
     if !self.vals.is_some() { 
      let look_for = self.look_for; 
      self.vals = Some(Box::new({ 
       self.display.chars().filter(move |&i| i == look_for) 
      })); 
     } 

     if let &Some(v) = &self.vals.as_mut().unwrap().next() { 
      Some(expensive(v)) 
     } else { 
      None 
     } 
    } 
} 

Явное приведение на Box не надо, так что я удалил его.

+0

'! Self.vals.is_some()' => 'self.vals.is_none()' и некоторая 'map' на последней строке также сделает его еще красивее. – Shepmaster

+0

Это начинает иметь смысл-спасибо за подробный ответ! Но у меня, похоже, есть проблемы с обобщением этого подхода: мой реальный сценарий больше похож на https://play.rust-lang.org/?gist=c43e28b29426cbc50982242f222599f8&version=nightly&backtrace=0, где я не просто хватаю поле, но * вызываю функция на себя, которая возвращает (значение, полученное из) поля. Есть ли подход, который работает в этой ситуации? – Bosh

+0

@Bosh: Если вы удаляете '' a' в '& 'self' в' look_for_details', он компилируется. –