rust语言学习笔记(指针十三) 其他补充

除了你列出的这些,Rust 标准库中还有一些常用或重要的指针/封装类型,它们常与智能指针一起出现,或在特定场景下替代智能指针的功能:

  • 裸指针 *const T /*mut T :无所有权、无生命周期管理的原始指针,用于与 C 交互、手写数据结构、避免借用检查器限制等场合。通常在 unsafe 块中使用。
  • NonNull<T>:保证非空的裸指针封装,用于实现更安全的集合和容器,很多标准库结构内部使用它。
  • MaybeUninit<T> :用于延迟初始化或处理未初始化内存,配合 Box::new_uninit 或手动初始化,常用于写 unsafe 数据结构或减少初始化开销。
  • UnsafeCell<T> :所有内部可变性的基础原语,CellRefCellMutex 等底层都依赖它,一般不直接使用,除非实现自定义同步原语。
  • OnceCell<T> / OnceLock<T> :一次性初始化单元格,写入后只能读取,OnceLock 是线程安全版本(类似 Mutex 但只写一次),常用于延迟初始化全局配置或常量。
  • LazyCell<T> / LazyLock<T> :在 OnceCell 基础上封装了闭包,首次访问时自动计算并缓存值,LazyLock 用于多线程,适合静态的延迟初始化复杂对象。
  • ManuallyDrop<T> :阻止编译器自动调用 Drop,用于需要手动控制资源释放的场景,或实现更复杂的析构逻辑。

这些类型与已列出的智能指针经常组合使用,形成适应不同所有权和并发需求的模式。下面是常见组合方式及适用环境:

组合模式 适用环境 典型场景
Rc<RefCell<T>> 单线程,多个所有者需要共享可变数据 图、树结构,GUI 中的共享状态,事件处理
Arc<Mutex<T>> 多线程,共享可变数据,互斥访问 线程间共享计数器、缓存、任务队列
Arc<RwLock<T>> 多线程,读多写少 缓存、配置、无锁数据结构
Rc<Vec<RefCell<T>>>Rc<RefCell<Vec<...>>> 单线程,共享可变集合 树的多子节点、链表节点管理
Weak<T> 配合 Rc/Arc 打破循环引用,避免内存泄漏 树结构中父节点指向子节点用 Rc,子节点指回父节点用 Weak;观察者模式
Pin<Box<T>>‌ 或 Pin<Arc<T>> 需要固定内存地址,不可移动 异步任务(Future)、自引用结构体
Cow<'_, T> 读多写少,需要避免不必要的克隆 字符串处理、配置解析、序列化
Box<dyn Trait> 运行时多态,类型擦除 插件系统、异构集合、动态分发
Cell<T> 用于简单 Copy 类型 单线程,只需要整体替换值 计数器、标志位、简单状态
OnceLock<T>LazyLock<T> 配合 Arc 线程安全的全局延迟初始化 静态配置、全局缓存、单例
MaybeUninit<T>Box 组合 延迟初始化堆上数据,避免重复初始化 实现 Vec 等容器,或需要分批填充的大数组
ManuallyDrop<T>Box 组合 手动控制析构时机 共享内存、外部资源管理、实现自定义 Drop

选择建议‌:

  • 单线程只读共享 → Rc<T>
  • 单线程共享可变 → Rc<RefCell<T>>
  • 多线程只读共享 → Arc<T>
  • 多线程共享可变 → Arc<Mutex<T>>(需要互斥)或 Arc<RwLock<T>>(读多写少)
  • 需要固定地址 → 结合 Pin
  • 需要打破循环引用 → 引入 Weak
  • 需要写时复制 → Cow
  • 需要一次性初始化 → OnceCell/OnceLock/LazyLock

这些组合覆盖了 Rust 中绝大多数所有权、可变性和并发场景,你可以根据实际需求灵活选用。