28·智能指针进阶

RefCell 与内部可变性

RefCell 与内部可变性

学习目标

  1. 理解内部可变性模式
  2. 掌握 RefCell<T> 的使用
  3. 理解 Cell<T>RefCell<T> 的区别
  4. 掌握 Rc<RefCell<T>> 组合

核心概念

为什么需要内部可变性?

// 正常情况下:不可变引用不能修改值
fn push_if_positive(v: &Vec<i32>, val: i32) {
    // v.push(val);  // ❌ v 是不可变引用
}

// 但有些场景需要在不可变引用下修改
// 比如:缓存、日志计数器等

RefCell<T>

use std::cell::RefCell;

fn main() {
    let data = RefCell::new(vec![1, 2, 3]);

    // 不可变借用
    {
        let borrowed = data.borrow();
        println!("{:?}", borrowed);
    }  // borrowed 离开作用域,释放借用

    // 可变借用
    {
        let mut borrowed_mut = data.borrow_mut();
        borrowed_mut.push(4);
    }

    println!("{:?}", data.borrow());
}

Cell<T>

use std::cell::Cell;

fn main() {
    let counter = Cell::new(0);

    counter.set(1);
    counter.set(counter.get() + 1);
    println!("计数: {}", counter.get());  // 2

    // Cell 适用于 Copy 类型
    // 没有借用检查,直接 get/set
}

Cell vs RefCell

类型类型限制借用方式性能
Cell<T>T: Copyget()/set()快(无借用检查)
RefCell<T>任意 Tborrow()/borrow_mut()有运行时检查

Rc<RefCell<T>>(共享可变状态)

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

#[derive(Debug)]
struct SharedState {
    value: i32,
    history: Vec<i32>,
}

fn main() {
    let state = Rc::new(RefCell::new(SharedState {
        value: 0,
        history: vec![],
    }));

    let state1 = Rc::clone(&state);
    let state2 = Rc::clone(&state);

    // 多个地方修改同一状态
    state1.borrow_mut().value = 1;
    state1.borrow_mut().history.push(1);

    state2.borrow_mut().value = 2;
    state2.borrow_mut().history.push(2);

    println!("最终状态: {:?}", state.borrow());
}

观察者模式

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

trait Observer {
    fn notify(&self, message: &str);
}

struct Logger;
impl Observer for Logger {
    fn notify(&self, message: &str) {
        println!("[LOG] {}", message);
    }
}

struct EventEmitter {
    observers: Vec<Rc<dyn Observer>>,
}

impl EventEmitter {
    fn new() -> Self {
        EventEmitter { observers: vec![] }
    }

    fn subscribe(&mut self, observer: Rc<dyn Observer>) {
        self.observers.push(observer);
    }

    fn emit(&self, message: &str) {
        for observer in &self.observers {
            observer.notify(message);
        }
    }
}

fn main() {
    let emitter = Rc::new(RefCell::new(EventEmitter::new()));
    let logger = Rc::new(Logger);

    emitter.borrow_mut().subscribe(logger);
    emitter.borrow().emit("事件发生");
}

实践练习

练习 1:可缓存结构

use std::cell::RefCell;

struct ExpensiveComputation {
    cache: RefCell<Option<i32>>,
}

impl ExpensiveComputation {
    fn new() -> Self {
        ExpensiveComputation { cache: RefCell::new(None) }
    }

    fn compute(&self, input: i32) -> i32 {
        if let Some(cached) = *self.cache.borrow() {
            println!("使用缓存");
            return cached;
        }
        println!("重新计算...");
        let result = input * input;  // 假设很耗时
        *self.cache.borrow_mut() = Some(result);
        result
    }
}

fn main() {
    let comp = ExpensiveComputation::new();
    println!("结果: {}", comp.compute(5));
    println!("结果: {}", comp.compute(5));
}

练习 2:共享计数器

use std::rc::Rc;
use std::cell::Cell;

fn make_counter() -> (Rc<Cell<i32>>, impl Fn() -> i32) {
    let count = Rc::new(Cell::new(0));
    let count_clone = Rc::clone(&count);
    let increment = move || {
        count_clone.set(count_clone.get() + 1);
        count_clone.get()
    };
    (count, increment)
}

fn main() {
    let (count, increment) = make_counter();
    println!("{}", increment());  // 1
    println!("{}", increment());  // 2
    println!("{}", increment());  // 3
    println!("最终: {}", count.get());
}

常见错误

1. 运行时借用冲突

use std::cell::RefCell;

let data = RefCell::new(5);
let r1 = data.borrow();
let r2 = data.borrow_mut();  // ❌ panic: already borrowed

2. 忘记释放借用

let data = RefCell::new(vec![1, 2, 3]);
let borrowed = data.borrow();
// data.borrow_mut();  // ❌ borrowed 仍存活
drop(borrowed);  // ✅ 手动释放

小结

类型用途
Cell<T>Copy 类型的内部可变性
RefCell<T>任意类型的内部可变性(运行时检查)
Rc<RefCell<T>>共享可变状态

练习编辑器

rust
Loading...