Rust 学习笔记 19:智能指针 (Smart Pointers)

“Pointer, I choose you!”

在 C++ 中,为了管理内存,我们有 unique_ptrshared_ptr。 Rust 也有类似这一套,而且它是内存安全模型的重要补充。

普通引用 &T&mut T 只是单纯的借用,不拥有数据。 而智能指针通常拥有它们指向的数据。

1. Box

最简单的智能指针。它把数据分配在堆上,栈上只留一个指针。

1let b = Box::new(5);
2println!("b = {}", b);

用途

  1. 当类型大小在编译期无法确定时(比如递归类型 Cons List)。
  2. 当你拥有大量数据,想转移所有权但不想拷贝数据时。
  3. Trait Objects (Box<dyn Trait>)。

2. Deref 和 Drop Trait

智能指针之所以"智能",是因为它们实现了:

  • Deref Trait:允许像普通引用一样使用解引用运算符 *。这就是为什么 *b 能取到 5。
  • Drop Trait:允许自定义在清理时运行的代码(析构函数)。

3. Rc (引用计数)

Rc (Reference Counting) 允许数据有多个所有者。 比如图结构,一个节点可能被多条边指向。

1let a = Rc::new(5);
2let b = Rc::clone(&a); // 引用计数 +1
3let c = Rc::clone(&a); // 引用计数 +1

Rc::clone 不会深拷贝数据,只会增加引用计数。当所有 Rc 都离开作用域,计数归零,数据才被释放。 注意:Rc 只能用于单线程。多线程要用 Arc (Atomic Rc)。

4. RefCell (内部可变性)

Rust 的借用规则(要么多个不可变,要么一个可变)有时太严格了。 RefCell 允许你在运行时(而不是编译时)检查借用规则。

内部可变性 (Interior Mutability): 即使 RefCell 本身是不可变的,你也可以修改它包裹的值。

1let data = RefCell::new(5);
2*data.borrow_mut() += 1;

这常用于"不可变结构体中修改部分字段"(如 mock 对象记录调用次数)。

5. 小结

第十九篇笔记。

  • Box:独占所有权,堆分配。
  • Rc:多重所有权,引用计数。
  • RefCell:借用规则的动态检查,内部可变性。

下一篇,我们将实战第二个项目:minigrep。我们将综合运用至今学到的所有知识(所有权、错误处理、Trait、生命周期、迭代器、智能指针),写一个真正的命令行工具。


练习题

  1. Box 定义一个递归的 Cons List。
  2. 尝试构建一个导致 引用循环 (Reference Cycle) 的场景(使用 RcRefCell),并观察是否有内存泄漏(Drop 不会被调用)。然后学习如何用 Weak<T> 解决它。

思考题

Rust 为什么要把 RefCell 的检查推迟到运行时?这带来了什么代价?它和 C++ 的 mutable 关键字有何异同?


本文代码示例

关注公众号:极客老墨

更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。

极客老墨微信公众号二维码

相关阅读