You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 02:52:26