Rust 智能指针实战:用 Rc 与 RefCell 处理单线程共享可变状态

test12026-10-084 次阅读

为什么需要 Rc<RefCell<T>>

借用检查器默认禁止同一份数据出现多个可变引用。在单线程里,我们确实想让多个持有者共享并修改同一份状态(比如事件总线、DOM 树节点),这时就用 Rc 做共享所有权、用 RefCell 把借用检查推迟到运行时。

1 一个最小事件总线

订阅者以闭包形式存进 Rc<RefCell<Vec<...>>>,订阅和发布都通过 clone 出来的 Rc 操作同一份集合。

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

type Handler = Box<dyn Fn(&str)>;

struct EventBus {
    handlers: Rc<RefCell<Vec<Handler>>>,
}

impl EventBus {
    fn new() -> Self {
        Self { handlers: Rc::new(RefCell::new(Vec::new())) }
    }

    fn subscribe(&self, h: Handler) {
        self.handlers.borrow_mut().push(h);
    }

    fn emit(&self, msg: &str) {
        for h in self.handlers.borrow().iter() {
            h(msg);
        }
    }
}

2 父子共享同一份可变状态

把 Rc clone 给子节点,大家都能修改同一个计数器,且不需要把状态层层传参。

fn main() {
    let bus = EventBus::new();
    let b2 = bus.handlers.clone(); // 共享同一份 handlers

    bus.subscribe(Box::new(|m| println!("收到: {}", m)));
    bus.emit("hello");

    // b2 与 bus 指向同一数据
    println!("订阅数: {}", b2.borrow().len());
}

3 与 Arc<Mutex<T>> 的取舍

  • 确定只在单线程内共享可变状态,用 Rc<RefCell<T>>,零原子开销,运行时借用失败会 panic。
  • 需要跨线程共享,换成 Arc<Mutex<T>>(或 Arc<RwLock<T>>),把运行时借用检查升级为线程安全的互斥锁。
  • 若数据其实不可变,只用 Rc<T> 即可,不必引入 RefCell 的可变开销。
T

test1

文章作者

为什么需要 Rc<RefCell<T>> 借用检查器默认禁止同一份数据出现多个可变引用。在单线程里,我们确实想让多个持...

分类
技术
发布时间
2026-10-08
字数
约 1271 字
阅读
4 次