在 Rust 中,智能指针是管理内存的高级工具,它们不仅提供指针功能,还包含额外的元数据和能力(如所有权管理、引用计数等)。以下是 Rust 主要智能指针的全面解析:
特性 | 普通引用 (&T ) |
智能指针 |
---|---|---|
所有权 | 只借用数据 | 通常拥有数据所有权 |
功能 | 简单的内存访问 | 附加管理逻辑 |
内存位置 | 可指向栈或堆 | 通常管理堆内存 |
元数据 | 无 | 包含额外元数据 |
Box
:堆分配的最简指针作用:在堆上分配值,栈上存储指针
所有权:单一所有者
特点:
编译时已知大小(因为指针大小固定)
离开作用域自动释放内存
使用场景:
递归类型(如链表节点)
大数据转移所有权(避免复制)
trait 对象(Box
)
let boxed = Box::new(5); // 在堆上分配整数
let list = Cons(1, Box::new(Cons(2, Box::new(Nil)))); // 递归类型
Rc
:引用计数指针作用:多所有权共享数据
所有权:多个不可变引用
特点:
单线程使用
运行时引用计数
clone()
增加计数,离开作用域减少计数
使用场景:
共享只读数据
图结构、UI 组件树
use std::rc::Rc;
let shared = Rc::new(42);
let clone1 = Rc::clone(&shared);
let clone2 = Rc::clone(&shared);
// 所有克隆指向同一数据
RefCell
:内部可变性容器作用:在不可变引用中修改数据
所有权:运行时借用检查
特点:
单线程使用
绕过编译时借用检查(运行时检查)
使用 borrow()
和 borrow_mut()
访问
使用场景:
需要修改共享数据
模拟编译时无法确认的借用模式
use std::cell::RefCell;
let cell = RefCell::new(42);
{
let mut ref_mut = cell.borrow_mut(); // 运行时借用检查
*ref_mut += 10;
}
println!("{}", cell.borrow()); // 52
Arc
:原子引用计数作用:线程安全的引用计数
所有权:多线程共享
特点:
使用原子操作保证线程安全
比 Rc
性能略低
使用场景:
跨线程共享数据
常与 Mutex
配合使用
use std::sync::Arc;
use std::thread;
let shared = Arc::new(42);
let threads: Vec<_> = (0..5).map(|i| {
let arc_clone = Arc::clone(&shared);
thread::spawn(move || {
println!("Thread {}: {}", i, arc_clone);
})
}).collect();
for t in threads {
t.join().unwrap();
}
Mutex
:互斥锁作用:线程间安全共享可变数据
所有权:通过锁机制控制访问
特点:
提供内部可变性
阻塞等待锁释放
使用场景:
跨线程修改共享数据
常与 Arc
组合使用
use std::sync::{Arc, Mutex};
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("Result: {}", *counter.lock().unwrap()); // 10
Deref
Trait:解引用能力use std::ops::Deref;
struct MyBox(T);
impl Deref for MyBox {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
fn main() {
let my_box = MyBox(5);
assert_eq!(5, *my_box); // 通过Deref实现解引用
}
Drop
Trait:自定义清理struct CustomPointer {
data: String,
}
impl Drop for CustomPointer {
fn drop(&mut self) {
println!("Dropping: {}", self.data);
}
}
fn main() {
let _p = CustomPointer { data: "resource".into() };
// 离开作用域时打印 "Dropping: resource"
}
Rc>
:单线程共享可变数据use std::rc::Rc;
use std::cell::RefCell;
let shared_vec = Rc::new(RefCell::new(vec![1, 2, 3]));
// 克隆引用
let clone1 = Rc::clone(&shared_vec);
let clone2 = Rc::clone(&shared_vec);
// 在不同位置修改
clone1.borrow_mut().push(4);
clone2.borrow_mut().push(5);
println!("{:?}", shared_vec.borrow()); // [1, 2, 3, 4, 5]
Arc>
:多线程共享可变数据use std::sync::{Arc, Mutex};
use std::thread;
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..10 {
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut num = counter.lock().unwrap();
*num += 1;
});
handles.push(handle);
}
// 等待所有线程完成
for handle in handles {
handle.join().unwrap();
}
println!("Final count: {}", *counter.lock().unwrap()); // 10
场景需求 | 推荐智能指针 |
---|---|
单一所有权堆分配 | Box |
单线程共享不可变数据 | Rc |
单线程共享可变数据 | Rc |
多线程共享不可变数据 | Arc |
多线程共享可变数据 | Arc 或 Arc |
需要自定义析构行为 | 实现 Drop trait |
优先选择编译时检查:能用引用解决就不用智能指针
避免循环引用:
使用 Weak
打破 Rc
/Arc
循环
use std::rc::{Rc, Weak};
struct Node {
parent: RefCell>,
children: RefCell>>,
}
注意死锁风险:
避免在持有锁时调用可能再次请求锁的代码
性能考量:
RefCell
有运行时开销
Mutex
有加锁开销
替代方案:
考虑使用基于栈的 arena 分配器处理大量小对象
使用第三方库如 crossbeam
的高级并发工具
Rc
内存布局:[ strong count | weak count | data ]
----------- --------- ------
8字节 8字节 T大小
Arc
的原子操作:// 简化版原子计数
use std::sync::atomic::{AtomicUsize, Ordering};
struct ArcInner {
strong: AtomicUsize, // 原子计数器
data: T,
}
Mutex
实现伪代码:struct Mutex {
locked: AtomicBool, // 锁状态
data: UnsafeCell, // 内部可变性
}