← [ BACK_TO_NOTES ]

Rust 智能指针

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

#concept #growing #dev #rust

[!info] related notes

Rust 智能指针

这个概念为什么出现

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

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

智能指针通常封装所有权或访问管理,常与 Deref、Drop 配合;这不是“同时实现两个 trait”的严格分类。RefCell 是内部可变容器,并不靠直接 Deref 暴露 T,需借用守卫访问。

[!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. 跨线程共享还需满足内部类型的 Send/Sync 约束,不能只把 Rc 改名为 Arc

核心概念与准确模型

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

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

设计动机

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

边界与误区

  • Rc/Arc 的强引用环会泄漏;Weak 不维持底层 T 存活,upgrade 返回 Option,弱引用并不自动消除所有环
  • Arc 仅保证引用计数原子化;Arc 的 Send/Sync 通常要求 T: Send + Sync,Arc<RefCell> 不因此成为线程安全共享方案
  • Box 拥有数据但不会保证递归释放深度有界;零大小类型的 Box 不需要实际分配堆空间
  • RefCell 运行时 borrow panic
  • 不要默认 Arc<Mutex<...>> 万事大吉——争用与死锁仍在

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

工程实践

  1. 能 &T 就别 Rc
  2. 只有多个线程需要共同持有才用 Arc;独占转移可直接 move,作用域线程也可借用
  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/10/7
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本