std::rc 模块教程
Rust 的 std::rc
模块是标准库中实现单线程引用计数的根本组成部分,提供 Rc<T>
、Weak<T>
、RcBox
(内部)和相关 trait,用于管理共享所有权的对象生命周期,而不需垃圾回收。它抽象了底层原子/非原子计数机制(Rc 用 NonAtomicRefCell-like 计数),确保在单线程环境中的安全性和效率,并通过 std::rc::DowngradeError
或运行时 panic 显式处理错误如弱引用升级失败或循环引用导致的内存泄漏。std::rc
强调 Rust 的所有权模型扩展:允许多个不可变借用共享数据,通过引用计数在最后一个 Rc drop 时释放;支持弱引用(Weak)以打破循环引用,避免内存泄漏;泛型 T 要求 'static 以防借用逃逸。模块的设计优先低开销和简单性,适用于单线程共享数据场景(多线程用 std::sync::Arc),并提供 try_unwrap 以回收唯一所有权。std::rc
与 std::cell
(内部可变如 RefCell)、std::ptr
(指针操作)、std::mem
(内存管理)、std::clone
(Rc Clone 增计数)和 std::ops
(Deref 到 &T)深度集成,支持高级模式如树结构共享和弱引用缓存。
1. std::rc 简介
- 导入和高级结构:除了基本导入
use std::rc::{Rc, Weak};
,高级用法可包括use std::rc::RcBox;
以访问内部(unsafe)和use std::rc::alloc;
以自定义分配(alloc 特征)。模块的内部结构包括 Rc 的 NonAtomicUsize 计数(strong/weak)、RcBox 的布局(计数 + T)和 Weak 的 Option以防循环。 - 类型详解:
Rc<T>
:引用计数指针,支持 clone() 增 strong_count、downgrade() 到 Weak、get_mut(&mut self) 独占修改、make_mut(&mut self) CoW 修改、ptr_eq(&self, &other) 指针比较、strong_count/weak_count 查询。Weak<T>
:弱引用,支持 upgrade() 到 Option<Rc>、clone() 增 weak_count、不持所有权以破循环。 RcBox<T>
:内部箱(unsafe),包含 strong/weak 计数和 T。DowngradeError
:弱升级错误(future proposal),当前 upgrade None 表示释放。
- 函数和方法扩展:
Rc::new
创建、Rc::try_unwrap
回收唯一、Rc::new_cyclic
循环创建、Rc::alloc
自定义分配 (alloc trait)。 - 宏:无,但相关如 std::rc 在宏扩展用于 rc! (future proposal)。
- 类型详解:
- 设计哲学扩展:
std::rc
遵循 "shared immutable",通过计数 drop 时释放;弱防循环泄漏;non-atomic 因单线程快 2x;make_mut CoW 优化修改。Rc 是 !Sync(非线程安全),强制单线程。 - 跨平台详解:计数用 std::sync::atomic fallback 非原子;Windows alloc 堆,Unix mmap;测试差异用 CI,焦点计数原子性。
- 性能详析:clone/drop ~10-20ns (计数 inc/dec);make_mut CoW 分配于修改;大 T clone 浅拷贝;weak upgrade <50ns。
- 常见用例扩展:树/图共享节点(文件系统模型)、缓存 Rc
、GUI 组件树、游戏实体引用、测试 mock 共享。 - 超级扩展概念:与 std::cell::RefCell 集成内部可变;与 std::panic::catch_unwind 安全 drop;错误无但循环 OOM,用 weak_count 监控;与 alloc_rc no_std 替代;高性能用 qrc (crate) 快速 Rc;与 tracing::field Rc 日志;历史:从 1.0 Rc 到 1.58 make_mut 优化。
2. 创建 Rc:Rc::new 和 Rc::from
Rc::new
是入口,Rc::from
转换。
示例:基本 Rc 创建(共享扩展)
use std::rc::Rc; fn main() { let rc = Rc::new(42); let rc2 = Rc::clone(&rc); println!("值: {}", *rc); // deref println!("强计: {}", Rc::strong_count(&rc)); // 2 }
- 解释:
new
分配 RcBox。clone
增计数。性能:分配 heap。
示例:Rc::new_cyclic(循环创建扩展)
use std::rc::Rc; use std::cell::RefCell; type Node = Rc<RefCell<Option<Node>>>; fn main() { let node = Rc::new_cyclic(|weak| RefCell::new(Some(weak.clone().upgrade().unwrap()))); println!("强: {}", Rc::strong_count(&node)); // 1 (循环但 weak 不计) }
- 解释:
new_cyclic
用 Weak 初始化防计数 1。扩展:用于链表/树自引用。
示例:Rc::alloc(自定义分配扩展)
use std::rc::Rc; use std::alloc::Global; fn main() { let rc = Rc::allocate_in(42, Global); println!("分配: {}", *rc); }
- 解释:
allocate_in
用 Allocator (alloc trait)。扩展:用 Bump allocator 快分配。
示例:Rc::from(转换扩展)
use std::rc::Rc; fn main() { let rc_str = Rc::<str>::from("hello"); println!("str: {}", rc_str); let rc_slice = Rc::from([1, 2, 3] as [i32; 3]); println!("slice: {:?}", rc_slice); }
- 解释:
from
专化 str/[T]。性能:零拷贝于 Box。
3. 操作 Rc:Clone、Downgrade、MakeMut
操作管理计数和修改。
示例:Clone 和 Count(引用扩展)
use std::rc::Rc; fn main() { let rc = Rc::new(vec![1]); let rc2 = rc.clone(); println!("强: {}", Rc::strong_count(&rc)); // 2 drop(rc2); println!("强: {}", Rc::strong_count(&rc)); // 1 }
- 解释:clone 原子 inc。drop dec,0 释放。
示例:Downgrade 和 Upgrade(弱引用扩展)
use std::rc::{Rc, Weak}; fn main() { let rc = Rc::new(42); let weak = Rc::downgrade(&rc); println!("弱计: {}", Rc::weak_count(&rc)); // 1 if let Some(strong) = weak.upgrade() { println!("升级: {}", *strong); } else { println!("释放"); } }
- 解释:
downgrade
创建 Weak。upgrade
如果 strong >0 返回 Some(Rc)。陷阱:drop rc 后 upgrade None。
示例:MakeMut 和 GetMut(修改扩展)
use std::rc::Rc; fn main() { let mut rc = Rc::new(vec![1, 2]); if Rc::strong_count(&rc) == 1 { let mut_data = Rc::get_mut(&mut rc).unwrap(); mut_data.push(3); } let mut_data2 = Rc::make_mut(&mut rc); mut_data2.push(4); // CoW 如果 >1 println!("vec: {:?}", rc); }
- 解释:
get_mut
&mut T 如果 unique。make_mut
CoW 克隆如果共享。性能:CoW 分配于修改。
示例:PtrEq 和 AsPtr(指针比较扩展)
use std::rc::Rc; fn main() { let rc1 = Rc::new(42); let rc2 = rc1.clone(); println!("指针等?{}", Rc::ptr_eq(&rc1, &rc2)); // true (同 RcBox) let ptr = Rc::as_ptr(&rc1); unsafe { println!("原始: {}", *ptr); } // 42 }
- 解释:
ptr_eq
比较指针。as_ptr
返回 *const T。unsafe 用于 deref。
4. Weak 操作:循环打破
Weak 防 Rc 循环泄漏。
示例:基本 Weak(树节点扩展)
use std::rc::{Rc, Weak}; use std::cell::RefCell; struct Node { value: i32, parent: RefCell<Weak<Node>>, children: RefCell<Vec<Rc<Node>>>, } fn main() { let leaf = Rc::new(Node { value: 3, parent: RefCell::new(Weak::new()), children: RefCell::new(vec![]), }); let branch = Rc::new(Node { value: 5, parent: RefCell::new(Weak::new()), children: RefCell::new(vec![Rc::clone(&leaf)]), }); *leaf.parent.borrow_mut() = Rc::downgrade(&branch); println!("叶强: {}", Rc::strong_count(&leaf)); // 2 (branch 子 + leaf) println!("叶弱: {}", Rc::weak_count(&leaf)); // 0 drop(branch); println!("叶强后: {}", Rc::strong_count(&leaf)); // 1 (弱不持) }
- 解释:Weak 作为 parent 破循环。drop branch 释放 leaf。
示例:Weak Count 和 Upgrade Error(监控扩展)
use std::rc::{Rc, Weak}; fn main() { let rc = Rc::new(()); let weak = Rc::downgrade(&rc); println!("弱计: {}", Rc::weak_count(&rc)); // 1 drop(rc); if let None = weak.upgrade() { println!("已释"); } }
- 解释:
weak_count
查询。upgrade None 表示释放。
4. 高级:TryUnwrap、Leak 和 集成
- TryUnwrap:回收唯一。
示例:TryUnwrap 回收(所有权扩展)
use std::rc::Rc; fn main() { let rc = Rc::new(String::from("data")); if let Ok(s) = Rc::try_unwrap(rc) { println!("回收: {}", s); } else { println!("共享"); } }
- 解释:
try_unwrap
如果 strong==1 返回 Ok(T)。扩展:用 into_inner 类似。
示例:Rc::leak('static 泄漏扩展)
use std::rc::Rc; fn main() { let leaked = Rc::leak(Rc::new(42)); println!("泄漏: {}", leaked); // &i32 'static // 永不 drop }
- 解释:
leak
返回 &'static T,忘记计数。用于全局静态。
示例:与 RefCell 集成(内部可变扩展)
use std::rc::Rc; use std::cell::RefCell; fn main() { let shared = Rc::new(RefCell::new(vec![1, 2])); let borrow = shared.borrow(); println!("借用: {:?}", borrow); let mut mut_borrow = shared.borrow_mut(); mut_borrow.push(3); }
- 解释:RefCell 允许 mut 借用 Rc 共享。运行时检查 borrow。
4. 错误和循环:Weak 解决
循环 Rc 泄漏,用 Weak 破。
示例:循环检测(count 监控扩展)
use std::rc::Rc; fn main() { let a = Rc::new(()); let b = Rc::clone(&a); // 模拟循环 if Rc::strong_count(&a) > 1 { println!("潜在循环: {}", Rc::strong_count(&a)); } }
- 解释:监控 strong_count >预期检测泄漏。
5. OS 扩展和 Raw
Rc 无 OS,但指针集成。
示例:Raw Pointer(unsafe 扩展)
use std::rc::Rc; fn main() { let rc = Rc::new(42); let raw = Rc::into_raw(rc); unsafe { println!("raw: {}", *raw); } let rc_back = unsafe { Rc::from_raw(raw) }; }
- 解释:
into_raw
释放为 *const T。from_raw
恢复。unsafe 用于手动管理。
6. 高级主题:Cyclic、Leak 和 集成
- Cyclic:自引用。
示例:Cyclic 数据结构(图扩展)
use std::rc::{Rc, Weak}; use std::cell::RefCell; type GraphNode = Rc<RefCell<NodeData>>; struct NodeData { value: i32, neighbors: Vec<Weak<GraphNode>>, } fn main() { let node1 = Rc::new(RefCell::new(NodeData { value: 1, neighbors: vec![] })); let node2 = Rc::new(RefCell::new(NodeData { value: 2, neighbors: vec![] })); node1.borrow_mut().neighbors.push(Rc::downgrade(&node2)); node2.borrow_mut().neighbors.push(Rc::downgrade(&node1)); // 无泄漏,因 Weak }
- 解释:Weak 邻居破循环。
7. 最佳实践和常见陷阱
- Rc 最佳:用 Weak 防循环;make_mut CoW 优化;ptr_eq 快比较。
- 性能:Rc clone 快于 Box;weak upgrade 检查 strong。
- 错误:循环 OOM,用 count 监控。
- 安全:Rc !Sync,防线程;RefCell 运行时借用。
- 跨平台:计数一致。
- 测试:miri 检测泄漏;fuzz Rc 操作。
- 资源:drop 释放;leak 故意静态。
- 常见扩展:
- 循环:Weak 解决。
- 多线程:用 Arc。
- 修改共享:RefCell panic 用 catch。
- 溢出:大 Rc count panic。
8. 练习建议
- 编写树:用 Rc 节点,Weak 父。
- 实现缓存:Rc<RefCell
> 共享。 - 创建自引用:new_cyclic 链表。
- 处理泄漏:用 weak_count 检测循环。
- 基准:比较 Rc vs Arc clone 时间,用 criterion。
- 与 cell:用 Rc<RefCell
> 多借用 push。 - 错误框架:mock循环测试 Weak 释放。
- 高级 app:实现 GUI 组件树:Rc
共享渲染。