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

如何避免Rust中的多次可变借用问题?

Rust可变借用冲突的解决方案

问题代码

use std::collections::HashMap;

struct A {
    a: i32
}

impl A {
    fn fun1(&mut self, i: i32) {
        println!("fun1: {}, {}", i, self.a);
    }
    
    fn fun2(&mut self, i: i32) {
        println!("fun2: {}, {}", i, self.a);
    }
}

fn main() {
    let mut a_obj = A {
        a: 9
    };
    
    let mut l: HashMap<String, Box<dyn FnMut(i32)>> = HashMap::new();
    l.insert(String::from("abc"), Box::new(|param| a_obj.fun1(param)));
    l.insert(String::from("def"), Box::new(|param| a_obj.fun2(param)));
    
    let key1 = String::from("abc");
    let h1 = l.get_mut(&key1).unwrap();
    h1(3);
    
    let key2 = String::from("def");
    let h2 = l.get_mut(&key2).unwrap();
    h2(686);
}

报错信息

error[E0499]: cannot borrow a_obj as mutable more than once at a time
--> src/main.rs:24:44
|
23 | l.insert(String::from("abc"), Box::new(|param| a_obj.fun1(param)));
| ------- ----- first borrow occurs due to use of a_obj in closure
| |
| first mutable borrow occurs here
24 | l.insert(String::from("def"), Box::new(|param| a_obj.fun2(param)));
| ^^^^^^^ ----- second borrow occurs due to use of a_obj in closure
| |
| second mutable borrow occurs here
...
27 | let h1 = l.get_mut(&key1).unwrap();
| ---------------- first borrow later used here

For more information about this error, try rustc --explain E0499.

问题原因

Rust的借用检查器严格遵循「同一时间只能存在一个可变引用」的规则。这里两个闭包在创建时都捕获了a_obj的可变引用,相当于同时持有两个活跃的可变借用,直接触发编译错误。加上闭包被存储在HashMap中,生命周期被延长,借用状态会持续到闭包被调用,进一步加剧了冲突。

解决方案:使用内部可变性(RefCell)

通过RefCell实现内部可变性,允许在共享引用的基础上,运行时动态获取可变引用,绕开编译期的借用检查(运行时会验证借用规则,违反时触发panic)。

修改后的代码:

use std::collections::HashMap;
use std::cell::RefCell;

struct A {
    a: i32
}

impl A {
    fn fun1(&mut self, i: i32) {
        println!("fun1: {}, {}", i, self.a);
    }
    
    fn fun2(&mut self, i: i32) {
        println!("fun2: {}, {}", i, self.a);
    }
}

fn main() {
    let a_obj = RefCell::new(A { a: 9 });
    
    let mut l: HashMap<String, Box<dyn FnMut(i32)>> = HashMap::new();
    l.insert(String::from("abc"), Box::new(|param| a_obj.borrow_mut().fun1(param)));
    l.insert(String::from("def"), Box::new(|param| a_obj.borrow_mut().fun2(param)));
    
    let key1 = String::from("abc");
    let h1 = l.get_mut(&key1).unwrap();
    h1(3);
    
    let key2 = String::from("def");
    let h2 = l.get_mut(&key2).unwrap();
    h2(686);
}

关键修改点

  • 导入std::cell::RefCell模块
  • 将a_obj声明为RefCell<A>,无需mut修饰,内部可变性由RefCell管理
  • 闭包中通过a_obj.borrow_mut()临时获取可变引用,每次调用闭包时才创建借用,避免了同时持有多个可变引用的情况

运行结果

执行后会输出:

fun1: 3, 9
fun2: 686, 9

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.16 23:53:20