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

Rust借用错误求解:无法多次可变借用及可变与不可变借用冲突

问题描述

我写了这段Rust代码:

let mut errors: Vec<String> = Vec::new();

let msg1 = "message 1".to_string();
let msg2 = "message 2".to_string();
let msg3 = "message 3".to_string();

let mut push_auth_requirements = || {
    errors.push(msg1.clone());
    errors.push(msg2.clone());
};

let mut push_auth_error = || {
    errors.push(msg3.clone());
    push_auth_requirements();
};

// do some stuff

if errors.is_empty() {
    // do more stuff
    if "bob" == "dsadasd" {
        push_auth_requirements();
    } else {
        push_auth_error();
    }
}

println!("Errors: {:?}",errors);

运行后报了两个错误:

error[E0499]: cannot borrow `errors` as mutable more than once at a time
  --> src/main.rs:89:31
   |
84 |     let mut push_auth_requirements = || {
   |                                      -- first mutable borrow occurs here
85 |         errors.push(msg1.clone());
   |         ------ first borrow occurs due to use of `errors` in closure
...
89 |     let mut push_auth_error = || {
   |                               ^^ second mutable borrow occurs here
90 |         errors.push(msg3.clone());
   |         ------ second borrow occurs due to use of `errors` in closure
91 |         push_auth_requirements();
   |         ---------------------- first borrow later captured here by closure

error[E0502]: cannot borrow `errors` as immutable because it is also borrowed as mutable
  --> src/main.rs:96:8
   |
84 |     let mut push_auth_requirements = || {
   |                                      -- mutable borrow occurs here
85 |         errors.push(msg1.clone());
   |         ------ first borrow occurs due to use of `errors` in closure
...
96 |     if errors.is_empty() {
   |        ^^^^^^ immutable borrow occurs here
...
99 |             push_auth_requirements();
   |             ---------------------- mutable borrow later used here

我想让两个闭包都能修改errors这个向量,该怎么解决这些错误?

解决方法

这是Rust借用检查器在起作用——它不允许同时存在多个可变引用,也不允许可变引用和不可变引用同时存在。要让多个闭包共享并修改同一个向量,得用内部可变性特性,再结合共享所有权的工具。

单线程场景:用Rc<RefCell<Vec<String>>>

Rc能让多个变量共享同一个值的所有权,RefCell则把借用检查从编译期移到运行期,允许我们在持有不可变引用的情况下修改内部数据。

改完的代码是这样的:

use std::rc::Rc;
use std::cell::RefCell;

fn main() {
    // 把普通Vec包进Rc和RefCell里
    let errors = Rc::new(RefCell::new(Vec::new()));

    let msg1 = "message 1".to_string();
    let msg2 = "message 2".to_string();
    let msg3 = "message 3".to_string();

    // 克隆Rc指针,给第一个闭包用
    let errors_clone1 = Rc::clone(&errors);
    let mut push_auth_requirements = move || {
        // 用borrow_mut()获取可变引用,修改内部向量
        errors_clone1.borrow_mut().push(msg1.clone());
        errors_clone1.borrow_mut().push(msg2.clone());
    };

    // 再克隆一个Rc给第二个闭包
    let errors_clone2 = Rc::clone(&errors);
    let mut push_auth_error = move || {
        errors_clone2.borrow_mut().push(msg3.clone());
        push_auth_requirements();
    };

    // do some stuff

    // 用borrow()获取不可变引用,检查是否为空
    if errors.borrow().is_empty() {
        // do more stuff
        if "bob" == "dsadasd" {
            push_auth_requirements();
        } else {
            push_auth_error();
        }
    }

    // 打印时同样用borrow()获取不可变引用
    println!("Errors: {:?}", errors.borrow());
}

多线程场景:用Arc<Mutex<Vec<String>>>

如果你的代码要在多线程里跑,就把Rc<RefCell>换成Arc<Mutex>——Arc是线程安全的共享所有权工具,Mutex保证同一时间只有一个线程能访问内部数据:

use std::sync::{Arc, Mutex};

fn main() {
    let errors = Arc::new(Mutex::new(Vec::new()));

    let msg1 = "message 1".to_string();
    let msg2 = "message 2".to_string();
    let msg3 = "message 3".to_string();

    let errors_clone1 = Arc::clone(&errors);
    let mut push_auth_requirements = move || {
        // 用lock()获取锁,得到可变引用
        let mut err = errors_clone1.lock().unwrap();
        err.push(msg1.clone());
        err.push(msg2.clone());
    };

    let errors_clone2 = Arc::clone(&errors);
    let mut push_auth_error = move || {
        let mut err = errors_clone2.lock().unwrap();
        err.push(msg3.clone());
        // 必须先释放锁,再调用另一个闭包,不然会死锁
        drop(err);
        push_auth_requirements();
    };

    // do some stuff

    if errors.lock().unwrap().is_empty() {
        // do more stuff
        if "bob" == "dsadasd" {
            push_auth_requirements();
        } else {
            push_auth_error();
        }
    }

    println!("Errors: {:?}", errors.lock().unwrap());
}

注意多线程里调用push_auth_requirements前一定要先释放当前的锁,不然两个闭包会互相等对方释放锁,导致死锁。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:55:02