RefCell 与内部可变性
学习目标
- 理解内部可变性模式
- 掌握
RefCell<T> 的使用
- 理解
Cell<T> 和 RefCell<T> 的区别
- 掌握
Rc<RefCell<T>> 组合
核心概念
为什么需要内部可变性?
fn push_if_positive(v: &Vec<i32>, val: i32) {
}
RefCell<T>
use std::cell::RefCell;
fn main() {
let data = RefCell::new(vec![1, 2, 3]);
{
let borrowed = data.borrow();
println!("{:?}", 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());
}
Cell vs RefCell
| 类型 | 类型限制 | 借用方式 | 性能 |
|---|
Cell<T> | T: Copy | get()/set() | 快(无借用检查) |
RefCell<T> | 任意 T | borrow()/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());
println!("{}", increment());
println!("{}", increment());
println!("最终: {}", count.get());
}
常见错误
1. 运行时借用冲突
use std::cell::RefCell;
let data = RefCell::new(5);
let r1 = data.borrow();
let r2 = data.borrow_mut();
2. 忘记释放借用
let data = RefCell::new(vec![1, 2, 3]);
let borrowed = data.borrow();
drop(borrowed);
小结
| 类型 | 用途 |
|---|
Cell<T> | Copy 类型的内部可变性 |
RefCell<T> | 任意类型的内部可变性(运行时检查) |
Rc<RefCell<T>> | 共享可变状态 |