Self being consumed by iterator, can't borrow

This:

  pub fn parse(&mut self) -> Result<Option<Rc<RefCell<Spec<C>>>>, ErrKind<C>> {
    for n in self {
      let spec = n.borrow();
      if spec.exit == true {
        return Ok(Some(Rc::clone(&n)));
      }
    }
    self.validate()?;
    Ok(None)
  }

.. causes this:

Summary
error[E0382]: borrow of moved value: `self`
   --> src/parser.rs:146:5
    |
137 |   pub fn parse(&mut self) -> Result<Option<Rc<RefCell<Spec<C>>>>, ErrKind<C>> {
    |                --------- move occurs because `self` has type `&mut parser::Parser<'_, C>`, which does not implement the `Copy` trait
138 |     for n in self {
    |              ----
    |              |
    |              value moved here
    |              help: consider borrowing to avoid moving into the for loop: `&self`
...
146 |     self.validate()?;
    |     ^^^^ value borrowed here after move

error: aborting due to previous error

Following the tips from the compiler causes:

Summary
error[E0277]: `&&mut parser::Parser<'a, C>` is not an iterator
   --> src/parser.rs:138:14
    |
138 |     for n in &self {
    |              -^^^^
    |              |
    |              `&&mut parser::Parser<'a, C>` is not an iterator
    |              help: consider removing the leading `&`-reference
    |
    = help: the trait `std::iter::Iterator` is not implemented for `&&mut parser::Parser<'a, C>`
    = note: `std::iter::Iterator` is implemented for `&mut &mut parser::Parser<'a, C>`, but not for `&&mut parser::Parser<'a, C>`
    = note: required by `std::iter::IntoIterator::into_iter`

The Parser implements:

impl<'a, C> Iterator for Parser<'a, C> {
  type Item = Rc<RefCell<Spec<C>>>;

  fn next(&mut self) -> Option<Self::Item> {
    match self.next() {
      Ok(res) => { return res; },
      Err(err) => {
        self.err = Some(err);
        return None;
      }
    }
  }
}

I'm a little confused -- what do I need to implement to allow the iterator to borrow self, allowing self.validate() to be called after the iterator?

Hmm.. I think I may have been thinking about iterators the wrong way.

So is Iterator something that makes the object itself iterable, while IntoIterator is used to create a proxy-object that does the iteration (the idea being that the object can be iterated over again)?

1 Like

It's almost correct. Iterator can't be iterated over again in the general case, it'll be unusable after being exhausted - that's why the cycle adapter requires the original iterator to be clonable, so that it can iterate over clones, storing the original one.

"Almost", because IntoIterator's into_iter method in general consume the original object. But it can be implemented for reference, and in this case it will be exactly what you describe: a proxy object referencing the original one.

1 Like

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.