简体   繁体   中英

Fighting with / not understanding Rust borrow checker

I started writing Rust code a few days ago, and just now had my first encounter with the borrow checker.

#[derive(Clone, Eq, Debug, PartialEq)]
pub struct Vm<'a> {
    instructions: Rc<InstructionSequence>,
    pc: usize,
    stack: Vec<Value<'a>>,
    frames: Vec<Frame<'a>>,
}

impl<'a> Vm<'a> {
    pub fn run(&'a mut self) {
        loop {
            let instruction = self.instructions.get(self.pc).unwrap();

            match instruction {
                &Instruction::Push(ref value) => {
                    let top_activation = &mut self.frames.last_mut().unwrap().activation;
                    self.stack.push(Vm::literal_to_value(value, top_activation))
                },

                _ => ()
            };
        };
    }
}

full code here

Rust gives me the following errors:

error[E0499]: cannot borrow `self.frames` as mutable more than once at a time
   --> src/vm.rs:157:47
    |
157 |                     let top_activation = &mut self.frames.last_mut().unwrap().activation;
    |                                               ^^^^^^^^^^^
    |                                               |
    |                                               second mutable borrow occurs here
    |                                               first mutable borrow occurs here
...
181 |     }
    |     - first borrow ends here

error[E0499]: cannot borrow `self.frames` as mutable more than once at a time
   --> src/vm.rs:157:47
    |
157 |                     let top_activation = &mut self.frames.last_mut().unwrap().activation;
    |                                               ^^^^^^^^^^^
    |                                               |
    |                                               second mutable borrow occurs here
    |                                               first mutable borrow occurs here
...
181 |     }
    |     - first borrow ends here

error: aborting due to 2 previous errors

I don't understand why it's getting borrowed twice. What's going on?

The value you push on the stack keeps a mutable borrow on self.frames active. On the second loop iteration, that borrow is still active, so you can't take a second borrow on self.frames .

Vm::literal_to_value doesn't need a mutable reference to the activation object, so you can change your code to take an immutable reference instead:

match instruction {
    &Instruction::Push(ref value) => {
        let top_activation = &self.frames.last().unwrap().activation;
        self.stack.push(Vm::literal_to_value(value, top_activation))
    },
    _ => ()
};

That makes run compile, but then your tests fail to compile. That's because with this signature:

pub fn run(&'a mut self)

you're linking the lifetime of self with the lifetime parameter on Vm . Essentially, the type of self here is &'a mut Vm<'a> ; the fact that 'a occurs twice here, combined with the fact that it's a mutable borrow (rather than an immutable borrow) tells Rust that the Vm maintains a mutable borrow on itself within one of its fields . Therefore, the Vm object will "lock" itself once you call run . That means that after calling run , you can't do anything else on the Vm ! The bottom line is that you can't have a field in a struct that is a reference to a value that is owned by the same struct .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM