如何在多个Rust闭包中使用可变借用?
你尝试用两个闭包修改同一个外部可变变量的代码如下:
let mut i: i32 = 0; let mut add = || { i += 1; }; let mut sub = || { i -= 1; }; add(); sub();
这段代码编译失败,报错信息如下:
error[E0499]: cannot borrow
ias mutable more than once at a time
--> src/main.rs:14:19
|
11 | let mut add = || {
| -- first mutable borrow occurs here
12 | i += 1;
| - first borrow occurs due to use ofiin closure
13 | };
14 | let mut sub = || {
| ^^ second mutable borrow occurs here
15 | i -= 1;
| - second borrow occurs due to use ofiin closure
16 | };
17 | add();
| --- first borrow later used here
这是因为Rust的借用规则禁止同一时间对同一个变量存在多个可变借用,而每个闭包都试图获取i的可变借用,导致冲突。以下是几种可行的解决方法:
1. 单线程场景:使用RefCell
RefCell提供内部可变性,允许在持有不可变引用的同时修改内部数据,它通过运行时的借用检查来保证安全(如果违反规则会 panic)。
use std::cell::RefCell; let i = RefCell::new(0); let mut add = || { *i.borrow_mut() += 1; }; let mut sub = || { *i.borrow_mut() -= 1; }; add(); sub(); println!("{}", *i.borrow()); // 输出0
2. 针对Copy类型:使用Cell
如果你的变量是Copy类型(比如i32、bool这类可以直接复制的类型),可以用更轻量的Cell,它不需要借用操作,直接通过get和set来读写值:
use std::cell::Cell; let i = Cell::new(0); let mut add = || { i.set(i.get() + 1); }; let mut sub = || { i.set(i.get() - 1); }; add(); sub(); println!("{}", i.get()); // 输出0
3. 多线程场景:使用Arc<Mutex>
如果闭包需要在多线程环境中运行,需要结合Arc(原子引用计数,用于多线程共享所有权)和Mutex(互斥锁,保证同一时间只有一个线程能修改数据):
use std::sync::{Arc, Mutex}; use std::thread; let i = Arc::new(Mutex::new(0)); // 克隆Arc,传递给第一个线程 let i_clone = Arc::clone(&i); let add_handle = thread::spawn(move || { let mut num = i_clone.lock().unwrap(); *num += 1; }); // 再次克隆Arc,传递给第二个线程 let i_clone2 = Arc::clone(&i); let sub_handle = thread::spawn(move || { let mut num = i_clone2.lock().unwrap(); *num -= 1; }); // 等待线程执行完成 add_handle.join().unwrap(); sub_handle.join().unwrap(); println!("{}", *i.lock().unwrap()); // 输出0
内容的提问来源于stack exchange,提问作者Li Zichao

