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))
},
_ => ()
};
};
}
}
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.