Borrowing self as mutable more than once and lifetimes

struct Lexer<'chars> {
  chars: Option<Peekable<Chars<'chars>>>, 
  vanish: bool
}

 fn chomp(&mut self,stream: &mut Peekable<Chars<'chars>>) -> Option<char> {
    return loop {
      match stream.next() {
        None => {
          self.vanish = true;
          return None;
        }
        
        Some(valid) => {
          if !valid.is_whitespace() {
            break Some(valid);
          }
          
          continue;
         } 
      }
     };
  }
  
  fn next(&mut self) -> Option<Token> {
    if !self.ensure() {
      return None;
    }
    
    let mut stream = self.chars.as_mut().unwrap();
    let mut ch = '0';
    
    ch = self.chomp(&mut stream).unwrap();
     
error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> source_file.rs:59:10
   |
56 |     let mut stream = self.chars.as_mut().unwrap();
   |                      ---------- first mutable borrow occurs here
...
59 |     ch = self.chomp(&mut stream).unwrap();
   |          ^^^^ second mutable borrow occurs here
...
78 |   }
   |   - first borrow ends here

In my first attempts at learning Rust I came across two major obstacles, lifetime and the rule of borrowing mutable references. I would like to ask for help to get around this problem of borrowing self as mutable. In the code in question I cache the Peekable object and when I use self to call a method the compiler does not accept it. I believe that it does not allow because I can change the Peekable or even delete it making the previous cache invalid. But shouldn't Peekable's lifetime and compiler intelligence be enough to know that this won't be the case and allow me to make the call?

Extra: is my chomp function acceptable or is it written in a weird way overusing the language flexibility?

Can you post your self type?

Ok

The rule that the compiler uses is that a mutable reference always has exclusive access to what it points at, so your program fails because &mut self overlaps with stream, meaning that the access is not exclusive.


Is there any reason you are not just accessing it through self.chars? Then you would not need to pass it as an extra parameter.

Another option is to call it like this:

// Take ownership of lexer.chars, leaving a None in the lexer.
let mut chars = lexer.chars.take().unwrap();

// Pass reference to our local variable.
lexer.chomp(&mut chars);

// Put it back.
lexer.chars = Some(chars);
2 Likes

To access through self I would have to make a chain of calls, doing it all in a loop seems to be expensive. I didn't know you could "get" an object and then return it, thanks for the tip.

You wouldn't need to do it inside the loop. You could do this:

  fn chomp(&mut self) -> Option<char> {
    let stream = self.chars.as_mut().unwrap();
    loop {
      match stream.next() {
        None => {
          self.vanish = true;
          return None;
        }
        Some(valid) => {
          if !valid.is_whitespace() {
            return Some(valid);
          }
        } 
      }
    }
  }
2 Likes