战斗与/不理解Rust借用检查器

时间:2017-02-09 05:07:58

标签: rust

我几天前开始编写Rust代码,刚刚第一次遇到借用检查程序。

#[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给了我以下错误:

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

我不明白为什么要借两次。发生了什么事?

1 个答案:

答案 0 :(得分:1)

您在堆栈上推送的值会在self.frames处于活动状态时保持可变借位。在第二次循环迭代中,该借用仍处于活动状态,因此您无法在self.frames上进行第二次借用。

Vm::literal_to_value不需要对激活对象进行可变引用,因此您可以更改代码以获取不可变引用:

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

这会使run编译,但是你的测试无法编译。那是因为有了这个签名:

pub fn run(&'a mut self)

您将self的生命周期与Vm上的生命周期参数相关联。从本质上讲,此处self的类型为&'a mut Vm<'a>; 'a在这里出现两次的事实,再加上它是一个可变的借用(而不是一个不可变的借用)这一事实告诉Rust Vm 在其内部维持一个可变的借用其中一个领域。因此,Vm对象将锁定&#34;一旦你打电话给run,就会自己。这意味着在致电run后,您无法在Vm上执行任何其他操作!底线是you can't have a field in a struct that is a reference to a value that is owned by the same struct