Rust同一行多重可变借用报错:借检查器为何从外层调用开始?
为什么Rust借用检查器从最外层函数调用开始检查?
以下代码因违反Rust借用检查规则无法编译运行:
struct Foo; impl Foo { fn bar(&mut self, i: u8) { } fn baz(&mut self) -> u8 { 0 } } fn main() { let mut foo = Foo; foo.bar(foo.baz()) // --------^^^^^^^^^- // | | | // | | second mutable borrow occurs here // | first borrow later used by call // first mutable borrow occurs here }
编译器会提示:先发生了第一个可变借用(调用bar时获取&mut self),随后计算参数foo.baz()时又尝试获取第二个可变借用,违反了“同一时间只能存在一个可变借用”的规则。
而通过引入临时变量可以规避这个问题:
fn main() { let mut foo = Foo; let t = foo.baz(); foo.bar(t); }
这其实和借用检查器的“检查顺序”无关,本质是Rust函数调用的求值顺序规则:当调用方法时,会先求值方法的接收者(也就是self对应的表达式,这里是foo),再依次求值函数的各个参数。
具体到foo.bar(foo.baz())这个调用:
- 第一步,为了调用
bar方法,必须先获取foo的可变借用(&mut self),这个借用会持续到整个bar调用结束; - 第二步,才会去计算参数
foo.baz(),此时又需要获取foo的可变借用,这就和之前未释放的借用冲突了。
Rust没有选择“先计算所有参数再调用函数”的顺序,主要是为了保持求值逻辑的一致性和可预测性。这种顺序和大多数静态语言的设计逻辑一致——你得先确定要调用方法的对象,再准备参数去调用它,避免因求值顺序歧义导致的行为不一致问题。
而使用临时变量时,foo.baz()作为单独的语句执行,它的可变借用在语句执行完毕后就会立即释放,后续调用foo.bar(t)时再获取新的可变借用,自然就不会产生冲突。
内容的提问来源于stack exchange,提问作者kalkronline
相关产品推荐
相关产品推荐

