Rust 学习笔记 19:智能指针 (Smart Pointers)
“Pointer, I choose you!”
在 C++ 中,为了管理内存,我们有 unique_ptr 和 shared_ptr。
Rust 也有类似这一套,而且它是内存安全模型的重要补充。
普通引用 &T 和 &mut T 只是单纯的借用,不拥有数据。
而智能指针通常拥有它们指向的数据。
1. Box
最简单的智能指针。它把数据分配在堆上,栈上只留一个指针。
1let b = Box::new(5);
2println!("b = {}", b);
用途:
- 当类型大小在编译期无法确定时(比如递归类型 Cons List)。
- 当你拥有大量数据,想转移所有权但不想拷贝数据时。
- 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、生命周期、迭代器、智能指针),写一个真正的命令行工具。
练习题:
- 用
Box定义一个递归的ConsList。 - 尝试构建一个导致 引用循环 (Reference Cycle) 的场景(使用
Rc和RefCell),并观察是否有内存泄漏(Drop 不会被调用)。然后学习如何用Weak<T>解决它。
思考题:
Rust 为什么要把 RefCell 的检查推迟到运行时?这带来了什么代价?它和 C++ 的 mutable 关键字有何异同?
本文代码示例:
关注公众号:极客老墨
更多 AI 应用开发、工程实践和效率工具分享,欢迎扫码关注。
