Rust 智能指针

Box/Rc/Arc/RefCell 等智能指针如何改变所有权形状:堆分配、共享所有权与内部可变性入口。

#type / concept #status / growing #tech / dev #resource / rust

[!info] 关联笔记

Rust 智能指针

这个概念为什么出现

有时默认所有权形状不够:

  • 递归结构需要间接(Box
  • 多处共享只读所有权(Rc/Arc
  • 共享下内部可变(RefCell

智能指针是实现 Deref/Drop 的结构体,像指针又管理额外资源。

[!abstract] 一句话理解 Box<T> 独享堆分配;Rc/Arc 共享所有权(单/多线程);RefCell 提供运行时借用检查的内部可变性。

最小可运行示例

场景:配置树节点——堆上递归 + 共享只读配置块

解析器 AST 需要递归 Box;多模块共享同一份只读 Rc 配置快照。

use std::rc::Rc;

// 业务意图:演示 Box 递归与 Rc 共享。
// 教学点:Box 间接;Rc 克隆增加强引用计数。

#[derive(Debug)]
enum Expr {
    Num(i32),
    Add(Box<Expr>, Box<Expr>),
}

fn main() {
    let e = Expr::Add(Box::new(Expr::Num(1)), Box::new(Expr::Num(2)));
    println!("{e:?}");

    let cfg = Rc::new(String::from("region=cn"));
    let cfg2 = Rc::clone(&cfg);
    println!("cfg_count~ strong={} values={} / {}", Rc::strong_count(&cfg), cfg, cfg2);
}

建议运行:cargo run

期望输出包含:

Add(Num(1), Num(2))

以及 strong count 为 2 的打印。

结合场景再看三个关注点

  1. Box 让递归类型大小可知
  2. Rc::clone 便宜在增计数,不是深拷贝字符串
  3. 多线程共享换 Arc

核心概念与准确模型

类型用途
Box<T>堆分配、递归、大对象转移
Rc<T>单线程共享所有权
Arc<T>多线程共享所有权
RefCell<T>单线程内部可变
Mutex<T>多线程互斥内部可变

组合:Rc<RefCell<T>>Arc<Mutex<T>> 是常见模式。

设计动机

  • 保持安全的前提下扩展所有权图
  • RAII 管理计数与锁
  • 明确单线程/多线程工具边界

边界与误区

  • Rc 环需要 Weak
  • RefCell 运行时 borrow panic
  • 不要默认 Arc<Mutex<...>> 万事大吉——争用与死锁仍在

[!warning] 常见误区:用 Rc 逃避借用检查 共享所有权有成本与复杂度,优先普通借用。

工程实践

  1. &T 就别 Rc
  2. 线程边界用 Arc
  3. 内部可变优先审视设计
  4. 文档写清不变量

本节总结

  • 智能指针改变所有权形状
  • Box/Rc/Arc/RefCell 各有场景
  • 与并发章节衔接

自测题

  1. Rc 为何不是线程安全?
  2. Box&T 本质差别?
参考答案
  1. 引用计数更新非原子,未实现 Send/Sync 的完整保证组合。
  2. Box 拥有堆数据;&T 只借用已有所有者。

延伸阅读与资料来源

资料类型支撑内容
The Book — Smart Pointers官方书智能指针
std::boxed::Box标准库Box
std::rc::Rc标准库Rc
创建于 2026/7/15 更新于 2026/7/15