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

为何Rust借用检查器在Arc::get_mut返回None时无法释放引用?

Rust中Arc写时复制(COW)模式的借用检查错误修复

原代码

use std::sync::Arc;

struct Foo(Arc<Bar>);

#[derive(Clone)]
struct Bar;

impl Foo {
    fn bar_mut(&mut self) -> &mut Bar {
        match Arc::get_mut(&mut self.0) {
            Some(bar) => bar,
            None => {
                let new_bar = Bar::clone(&self.0);
                self.0 = Arc::new(new_bar);
                Arc::get_mut(&mut self.0).unwrap()
            }
        }
    }
}

fn main() {
    Foo(Arc::new(Bar)).bar_mut();
}

编译错误信息

执行cargo check时出现以下错误:

*  Executing task: cargo check 

    Checking testproj v0.1.0 (/home/dspyz/testproj)
error[E0502]: 无法将`self.0`不可变借用,因为它已被可变借用
  --> src/main.rs:13:42
   |
9  |       fn bar_mut(&mut self) -> &mut Bar {
   |                  - 我们将此引用的生命周期称为`'1`
10 |           match Arc::get_mut(&mut self.0) {
   |           -                  ----------- 在此处发生可变借用
   |  _________|
   | |
11 | |             Some(bar) => bar,
12 | |             None => {
13 | |                 let new_bar = Bar::clone(&self.0);
   | |                                          ^^^^^^^ 在此处发生不可变借用
...  |
16 | |             }
17 | |         }
   | |_________- 返回此值要求`self.0`被借用至生命周期`'1`

error[E0506]: 无法赋值给`self.0`,因为它已被借用
  --> src/main.rs:14:17
   |
9  |       fn bar_mut(&mut self) -> &mut Bar {
   |                  - 我们将此引用的生命周期称为`'1`
10 |           match Arc::get_mut(&mut self.0) {
   |           -                  ----------- 在此处借用`self.0`
   |  _________|
   | |
11 | |             Some(bar) => bar,
12 | |             None => {
13 | |                 let new_bar = Bar::clone(&self.0);
14 | |                 self.0 = Arc::new(new_bar);
   | |                 ^^^^^^ 对已借用的`self.0`进行赋值
15 | |                 Arc::get_mut(&mut self.0).unwrap()
16 | |             }
17 | |         }
   | |_________- 返回此值要求`self.0`被借用至生命周期`'1`

error[E0499]: 无法同时多次将`self.0`可变借用
  --> src/main.rs:15:30
   |
9  |       fn bar_mut(&mut self) -> &mut Bar {
   |                  - 我们将此引用的生命周期称为`'1`
10 |           match Arc::get_mut(&mut self.0) {
   |           -                  ----------- 第一次可变借用发生在此处
   |  _________|
   | |
11 | |             Some(bar) => bar,
12 | |             None => {
13 | |                 let new_bar = Bar::clone(&self.0);
14 | |                 self.0 = Arc::new(new_bar);
15 | |                 Arc::get_mut(&mut self.0).unwrap()
   | |                              ^^^^^^^^^^^ 第二次可变借用发生在此处
16 | |             }
17 | |         }
   | |_________- 返回此值要求`self.0`被借用至生命周期`'1`

Some errors have detailed explanations: E0499, E0502, E0506.
For more information about an error, try `rustc --explain E0499`.
error: could not compile `testproj` due to 3 previous errors

错误原因

Arc::get_mut(&mut self.0)产生的可变借用会被Rust借用检查器认定为在整个match块中持续有效(直到方法返回引用)。这导致None分支中所有对self.0的操作——不可变借用(克隆)、赋值、再次可变借用——都违反了Rust的借用规则,触发报错。

解决方案

方案1:手动转移所有权打破借用关系

使用std::mem::take将self.0的所有权临时转移,断开原借用关系:

use std::sync::Arc;
use std::mem::take;

struct Foo(Arc<Bar>);

#[derive(Clone)]
struct Bar;

impl Foo {
    fn bar_mut(&mut self) -> &mut Bar {
        let arc = take(&mut self.0);
        match Arc::get_mut(&mut arc.clone()) {
            Some(bar) => {
                self.0 = arc;
                bar
            }
            None => {
                let new_arc = Arc::new((*arc).clone());
                self.0 = new_arc;
                Arc::get_mut(&mut self.0).unwrap()
            }
        }
    }
}

fn main() {
    Foo(Arc::new(Bar)).bar_mut();
}

方案2:使用标准库内置方法(推荐)

Arc::make_mut方法原生实现了“写时复制”逻辑:当Arc是唯一引用时直接返回可变引用,否则克隆内部数据并返回新Arc的可变引用,完全替代手动实现:

use std::sync::Arc;

struct Foo(Arc<Bar>);

#[derive(Clone)]
struct Bar;

impl Foo {
    fn bar_mut(&mut self) -> &mut Bar {
        Arc::make_mut(&mut self.0)
    }
}

fn main() {
    Foo(Arc::new(Bar)).bar_mut();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 21:55:44