Fighting with / not understanding Rust borrow checker

旧街凉风 提交于 2020-01-07 06:28:08

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!