我有点困惑这里的问题是什么,或者更确切地说,为什么它发生在一个场景中,而不是在其他场景中。
我正在编写一个gameboy模拟器并实现一个递增寄存器的函数,这是函数,它工作正常,没有任何错误:
pub fn increment_reg8(
&mut self,
register_name: RegisterName,
register_byte: RegisterByteName,
) -> u64 {
let target_register = &mut self.registers[register_name][register_byte];
let original_value = *target_register;
*target_register += 1;
if *target_register == 0 {
self.set_flag(Flag::Zero);
} else {
self.clear_flag(Flag::Zero);
}
4
}
现在我已经尝试将if语句更改为
self.set_flag_to(Flag::Zero, *target_register == 0);
它和前面的if语句差不多
fn set_flag_to(&mut self, flag: Flag, value: bool) {
if value {
self.set_flag(flag);
} else {
self.clear_flag(flag);
}
}
为什么这种变化会产生双重借用错误?
1条答案
按热度按时间rqqzpn5f1#
这是一个有趣的角落情况下借用检查。
self
被两个东西使用:set_flag
(相当于clear_flag
)和target_register
,这是对self
内部数据的可变引用。让我们看看你的第一个例子。一个天真的借款检查员会拒绝这一点。
target_register
对self
的一部分具有可变引用,而set_flag
/clear_flag
需要对self
的全部具有可变访问,因此这是一个双重借用。但是Rust的借用检查器并不天真。很聪明。它发现
target_register
永远不会再被使用,因此它会自动删除该值,以便重新获得self
上的租约。Rust只是默默地将你的代码转换成这样。其中
drop
是std::mem::drop
。第二个例子。
同样,
set_flag_to
需要对self
的可变引用,而target_register
已经是对self
的可变引用。Rust中的参数计算顺序是从左到右,self.method()
语法就是语法糖。因此
self
参数被求值。这可变地借用了所有self
。Flag::Zero
并不复杂,所以它通过了借用检查器。但是 * 现在 * 我们需要再次访问target_register
。但是我们已经可变地借用了self
,所以我们不能这样做。由于我们需要target_register
* 在 *self
借用之后,我们不能像以前那样自动删除任何内容。如果您更改求值顺序,使
target_register
在self
之前求值,它将再次通过。这将通过借用检查器,因为Rust会默默地将其转换为
我们可以在最后一行需要时借用
&mut self
。