Learn
Rust/18-smart-pointers

智能指针

智能指针(smart pointer) 是实现了 Deref/Drop 等 trait 的复合类型,在「指针」之上附加了所有权、计数或借用检查等语义。

1. Box<T>:最简单的堆分配

Box 堆分配
fn main() {
    let b = Box::new(5);          // 把值放到堆上
    println!("{}", b);            // 像普通值一样用(Deref)
}

常见用途:递归类型、特大对象、trait 对象。

enum List {
    Cons(i32, Box<List>),         // 递归必须靠 Box 确定大小
    Nil,
}
ℹ️为什么递归类型需要 Box

编译器需知道类型大小。Box<List> 是指针(固定大小),打破无限递归,让 List 大小可知。

2. Rc<T>:引用计数共享

单所有权不够用时,Rc 允许多个地方共享同一份只读数据:

Rc 引用计数
use std::rc::Rc;
 
fn main() {
    let shared = Rc::new(String::from("hi"));
    let a = Rc::clone(&shared);   // 计数 +1,不是深拷贝
    let b = Rc::clone(&shared);
    println!("引用计数 = {}", Rc::strong_count(&shared));
    // a、b、shared 都指向同一数据
}
⚠️Rc 只能单线程

Rc 不是线程安全的(无 Sync)。多线程共享用 Arc。且 Rc 内部数据默认不可变——要可变需配合 RefCell。

3. RefCell<T>:运行时借用检查

普通借用检查在编译期;RefCell 把检查推迟到运行时,从而能在「看似不可变」的 API 里做可变操作:

RefCell 内部可变性
use std::cell::RefCell;
 
fn main() {
    let cell = RefCell::new(5);
    *cell.borrow_mut() += 1;       // 运行时可变借用
    println!("{}", cell.borrow()); // 运行时不可变借用
}
💡Rc + RefCell 组合很常见

Rc<RefCell<T>> = 多所有者 + 可内部可变。这是 Rust 中「共享可变状态」的常见模式,但违反借用规则会在运行时 panic。

4. 对比 Box / Rc / RefCell

类型所有权借用检查可变?
Box<T>单一编译期取决于 mut
Rc<T>多共享(只读)编译期否
RefCell<T>单一运行时内部可变

5. Deref 与 Drop

智能指针能「像值一样用」是因为 Deref(解引用自动穿透),离开作用域自动 drop 是因为 Drop。

🎯练习

用 Rc<RefCell<Vec<i32>>> 模拟共享可变列表:创建两个 Rc 克隆,从一个里 borrow_mut().push 添加元素,验证另一个也能看到变化。观察强引用计数。

小结

  • Box 堆分配,解决递归类型与 trait 对象大小问题
  • Rc 引用计数实现单线程多所有权共享(只读)
  • RefCell 把借用检查移到运行时,支持内部可变性
  • Rc<RefCell<T>> 是共享可变状态常用组合
  • 下一章看线程与并发 →