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::rcstd::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. 练习建议

  1. 编写树:用 Rc 节点,Weak 父。
  2. 实现缓存:Rc<RefCell> 共享。
  3. 创建自引用:new_cyclic 链表。
  4. 处理泄漏:用 weak_count 检测循环。
  5. 基准:比较 Rc vs Arc clone 时间,用 criterion。
  6. 与 cell:用 Rc<RefCell> 多借用 push。
  7. 错误框架:mock循环测试 Weak 释放。
  8. 高级 app:实现 GUI 组件树:Rc 共享渲染。