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

Rust可变/不可变借用冲突:两种写法为何编译结果不同?

Rust生命周期借用冲突问题解析

问题复现代码

编译失败的写法

struct Bar<'a> {
    foo: &'a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&mut self) {
        unimplemented!()
    }
    
    fn create_option_bar(&self) -> Option<Bar> { 
        unimplemented!() 
    }

    fn create_bar(&mut self) -> Bar {
        let option_bar = self.create_option_bar();
        if option_bar.is_some() {
            return option_bar.unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

编译成功的写法

fn can_guarantee_option_bar_will_be_some() -> bool {
    unimplemented!()
}

struct Bar<'a> {
    foo: &'a Foo,
}

struct Foo;

impl Foo {
    fn borrow_mut(&mut self) {
        unimplemented!()
    }
    
    fn create_option_bar(&self) -> Option<Bar> { 
        unimplemented!() 
    }

    fn create_bar(&mut self) -> Bar {
        if can_guarantee_option_bar_will_be_some() {
            return self.create_option_bar().unwrap();
        }
        self.borrow_mut();
        unimplemented!()
    }
}

编译失败的错误信息

error[E0502]: cannot borrow `*self` as mutable because it is also borrowed as immutable
  --> src/main.rs:44:9
   |
37 |     fn create_bar(&mut self) -> Bar {
   |                   - let's call the lifetime of this reference `'1`
...
41 |         if let Some(bar) = self.create_option_bar() {
   |                            ------------------------ immutable borrow occurs here
42 |             return bar;
   |                    --- returning this value requires that `*self` is borrowed for `'1`
43 |         }
44 |         self.borrow_mut();
   |         ^^^^^^^^^^^^^^^^^ mutable borrow occurs here

原因分析

第一种写法编译失败的原因

在create_bar函数中:

  1. 调用self.create_option_bar()时,会对self产生不可变借用,这个借用的生命周期需要和返回的Bar结构体中foo字段的引用生命周期绑定。
  2. 变量option_bar持有这个不可变借用的产物,编译器会认为这个借用的生命周期覆盖了option_bar存在的整个范围——也就是从定义到函数结束(编译器无法提前确定if分支后option_bar是否会被使用)。
  3. 当后续执行self.borrow_mut()时,self仍处于不可变借用的状态,违反了Rust的核心借用规则:同一时间不能同时存在可变借用和不可变借用,因此触发E0502错误。

第二种写法编译成功的原因

修改后的代码将判断逻辑与create_option_bar()的调用分离:

  1. 如果can_guarantee_option_bar_will_be_some()返回true,函数会直接调用self.create_option_bar().unwrap()并返回,后续的self.borrow_mut()不会执行——此时不可变借用的生命周期仅到返回值,不会影响后续代码。
  2. 如果进入else分支,self.create_option_bar()根本没有被调用,不存在对self的不可变借用,因此self.borrow_mut()的可变借用完全合法。
    编译器能清晰分析出两种分支下,不可变借用和可变借用不会同时存在,因此允许编译通过。

内容的提问来源于stack exchange,提问作者doliphin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 05:45:25