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 的打印。
结合场景再看三个关注点
- Box 让递归类型大小可知
- Rc::clone 便宜在增计数,不是深拷贝字符串
- 多线程共享换 Arc
核心概念与准确模型
| 类型 | 用途 |
|---|---|
Box<T> | 堆分配、递归、大对象转移 |
Rc<T> | 单线程共享所有权 |
Arc<T> | 多线程共享所有权 |
RefCell<T> | 单线程内部可变 |
Mutex<T> | 多线程互斥内部可变 |
组合:Rc<RefCell<T>>、Arc<Mutex<T>> 是常见模式。
设计动机
- 保持安全的前提下扩展所有权图
- RAII 管理计数与锁
- 明确单线程/多线程工具边界
边界与误区
Rc环需要WeakRefCell运行时 borrow panic- 不要默认
Arc<Mutex<...>>万事大吉——争用与死锁仍在
[!warning] 常见误区:用 Rc 逃避借用检查 共享所有权有成本与复杂度,优先普通借用。
工程实践
- 能
&T就别Rc - 线程边界用
Arc - 内部可变优先审视设计
- 文档写清不变量
本节总结
- 智能指针改变所有权形状
- Box/Rc/Arc/RefCell 各有场景
- 与并发章节衔接
自测题
Rc为何不是线程安全?Box与&T本质差别?
参考答案
- 引用计数更新非原子,未实现 Send/Sync 的完整保证组合。
- Box 拥有堆数据;&T 只借用已有所有者。
延伸阅读与资料来源
| 资料 | 类型 | 支撑内容 |
|---|---|---|
| The Book — Smart Pointers | 官方书 | 智能指针 |
| std::boxed::Box | 标准库 | Box |
| std::rc::Rc | 标准库 | Rc |