#Confusion with Mutable Borrows

9 messages · Page 1 of 1 (latest)

frank osprey
#

Hello! This is my first time using Rust, could someone please help me understand why this code is giving me the error: "cannot borrow *self as mutable more than once at a time second mutable borrow occurs here"

fn scan_string(&mut self) {
    if let Some(mut next_char) = self.source.peek() // first mutable borrow {
        while *next_char != '"' { // first borrow later used here
            if *next_char == '\n' {
                self.process_newline(); // error message is given here
            }
            self.advance(); // and here
            match self.source.peek() { // and here
                Some(c) => next_char = c,
                None => (), // todo error
            }
        }
    }
}

But something similar like this does not

fn skip_whitespace(&mut self, initial_char: char) {
    if initial_char == '\n' {
        self.process_newline();
    }
    if let Some(mut next_char) = self.source.peek() {
        while next_char.is_whitespace() {
            if *next_char == '\n' {
                self.process_newline();
            }

            self.advance();
            match self.source.peek() {
                Some(c) => next_char = c,
                None => return,
            }
        }
    }
}

For reference, every method on self here is mutable. Thanks in advance! 🙂

final void
#

the big-picture problem here is that peek() gives you a reference to the item — but there is no reason to keep a &char reference around

#

so you can avoid having a borrowing problem by dereferencing it earlier

#
if let Some(&(mut next_char)) = self.source.peek() {

or

if let Some(mut next_char) = self.source.peek().copied() {

now next_char is just a char

frank osprey
#

Oh true, I could have just copied! Ty

I'm still curious as to why the second function does not have the same issue. To me it appears to store the same mutable reference in next_char, then call other methods that mutate self like process_newline and advance

plucky condor
#

in the first one if you actually write None => todo!(), you don't get an error

frank osprey
#

Ohhhh that's pretty sneaky. So the issue in the first function is that it's possible for next_char to hold onto the same reference from the previous iteration, then while keeping that refernce, call another functuon that mutates self. And the reason why it's not a problem in the scope of a single iteration is because next_char is not accessed after I make those method calls, right?

final void
#

Yep.