问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/42128666/fighting-with-not-understanding-rust-borrow-checker