2
votes

I'm writing a lexer in Rust to learn, but I'm stuck with two "cannot move out of borrowed content [E0507]" errors.

I tried all the solutions out there, but nothing seems to work: RefCell, clone(), by_ref(), changing the &mut self to self or &self or mut self, or dereferencing.

Here is my code:

struct Snapshot {
    Index: u32,
}

struct Tokenizable<'a, T: 'a>
    where T: Iterator
{
    Index: u32,
    Items: &'a T,
    Snapshots: Vec<Snapshot>,
}

impl<'a, T> Tokenizable<'a, T>
    where T: Iterator
{
    fn new(items: &'a T) -> Tokenizable<'a, T> {
        Tokenizable {
            Index: 0,
            Items: items,
            Snapshots: Vec::new(),
        }
    }

    fn end(&mut self) -> bool {
        match self.Items.peekable().peek() {
            Some(c) => false,
            None => true,
        }
    }

    fn peek(&mut self) -> Option<&T::Item> {
        match self.Items.peekable().peek() {
            Some(c) => Some(c),
            None => None,
        }
    }
}

fn main() {}
error: cannot move out of borrowed content [E0507]
         match self.Items.peekable().peek() {
               ^~~~~~~~~~
help: see the detailed explanation for E0507

error: borrowed value does not live long enough
         match self.Items.peekable().peek() {
               ^~~~~~~~~~~~~~~~~~~~~
note: reference must be valid for the anonymous lifetime #1 defined on the block at 32:43...
     fn peek(&mut self) -> Option<&T::Item> {
         match self.Items.peekable().peek() {
             Some(c) => Some(c),
             None => None,
         }
     }
note: ...but borrowed value is only valid for the block at 32:43
     fn peek(&mut self) -> Option<&T::Item> {
         match self.Items.peekable().peek() {
             Some(c) => Some(c),
             None => None,
         }
     }

error: cannot move out of borrowed content [E0507]
         match self.Items.peekable().peek() {
               ^~~~~~~~~~
help: see the detailed explanation for E0507
2

2 Answers

4
votes

As you can see in the docs, the peekable function takes the iterator by value. Therefore it will only work if you own the iterator. However, in your code, Items is a shared reference to the iterator.

Solving this problem requires approaching it from a different angle. For instance, you could take the iterator by value in the constructor and adapt the struct to store the peekable iterator in the Items field.

1
votes

Basically, what is to be learned from here is the fact that over complicating things and over engineering things almost always does more harm than good.

Final fixed code:

use std::iter::Peekable;

struct Snapshot {
    index: u32
}

struct Tokenizable<T> where T: Iterator {
    index : u32,
    items : Peekable<T>,
    snapshots : Vec<Snapshot>,
}

impl<T> Tokenizable<T> where T: Iterator {
    fn new (items: T) -> Tokenizable<T>  {
        Tokenizable {
            index : 0,
            items : items.peekable (),
            snapshots : Vec::new (),
        }
    }

    fn end (&mut self) -> bool {
        match self.items.peek () {
            Some (c) => false,
            None => true
        }
    }

    fn peek (&mut self) -> Option<&<T as Iterator>::Item> {
        match self.items.peek () {
            Some (c) => Some (c),
            None => None
        }
    }
}

fn main () {
    let mut data = "Hello".chars ();
    let tokenizable = Tokenizable::new (data);
}