智能指针是拥有数据所有权的指针,除了指向数据外,还提供额外的功能。Rust标准库提供了多种智能指针,最常用的有Box<T>、Rc<T>、Arc<T>和RefCell<T>。
学习目标:掌握Box堆分配、Rc共享所有权、Arc线程安全共享、RefCell内部可变性、Deref/Drop特征
fn main() {
// 基本用法:将数据放到堆上
let b = Box::new(5);
println!("b = {}", b);
// 场景1:编译时大小未知的类型
enum List {
Cons(i32, Box<List>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
println!("链表创建成功");
// 遍历链表
fn sum_list(list: &List) -> i32 {
match list {
Cons(val, next) => val + sum_list(next),
Nil => 0,
}
}
println!("链表和: {}", sum_list(&list));
// 场景2:递归类型大小
println!("i32大小: {} 字节", std::mem::size_of::());
println!("Box大小: {} 字节", std::mem::size_of::>());
// 场景3:trait对象
trait Animal {
fn speak(&self) -> String;
}
struct Dog;
struct Cat;
impl Animal for Dog { fn speak(&self) -> String { "汪汪!".into() } }
impl Animal for Cat { fn speak(&self) -> String { "喵喵!".into() } }
let animals: Vec> = vec![
Box::new(Dog),
Box::new(Cat),
];
for a in &animals {
println!("{}", a.speak());
}
}
✅ 验证通过
当需要多个所有者共享同一数据时,使用Rc(Reference Counted):
use std::rc::Rc;
fn main() {
// Rc允许多个所有者
let data = Rc::new(vec![1, 2, 3, 4, 5]);
let d1 = Rc::clone(&data); // 增加引用计数,不复制数据
let d2 = Rc::clone(&data);
println!("引用计数: {}", Rc::strong_count(&data)); // 3
println!("d1: {:?}", *d1);
println!("d2: {:?}", *d2);
// 共享图结构
#[derive(Debug)]
enum Node {
Leaf(i32),
Branch {
value: i32,
children: Vec<Rc<Node>>,
},
}
let leaf1 = Rc::new(Node::Leaf(1));
let leaf2 = Rc::new(Node::Leaf(2));
let leaf3 = Rc::new(Node::Leaf(3));
// 两个分支共享leaf2
let branch1 = Rc::new(Node::Branch {
value: 10,
children: vec![Rc::clone(&leaf1), Rc::clone(&leaf2)],
});
let branch2 = Rc::new(Node::Branch {
value: 20,
children: vec![Rc::clone(&leaf2), Rc::clone(&leaf3)],
});
println!("branch1: {:?}", branch1);
println!("branch2: {:?}", branch2);
println!("leaf2引用计数: {}", Rc::strong_count(&leaf2)); // 3
drop(branch1); // branch1被drop
println!("leaf2引用计数(drop后): {}", Rc::strong_count(&leaf2)); // 2
}
✅ 验证通过
Arc<T>。
use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(vec![1, 2, 3, 4, 5]);
let mut handles = vec![];
for i in 0..3 {
let data_clone = Arc::clone(&data);
let handle = thread::spawn(move || {
println!("线程{}: 数据={:?}, 引用计数={}",
i, *data_clone, Arc::strong_count(&data_clone));
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("主线程引用计数: {}", Arc::strong_count(&data));
}
✅ 验证通过
有时你需要在对不可变引用的情况下修改数据。RefCell将借用检查从编译期推迟到运行期:
use std::cell::RefCell;
fn main() {
// RefCell允许在&self方法中修改内部数据
let data = RefCell::new(vec![1, 2, 3]);
// borrow() → 不可变借用(运行时检查)
// borrow_mut() → 可变借用(运行时检查)
data.borrow_mut().push(4); // 即使data不是mut!
println!("修改后: {:?}", data.borrow());
// 实际应用:模拟消息记录器
trait Messenger {
fn send(&self, msg: &str); // 注意: &self不是&mut self
}
struct MockMessenger {
sent_messages: RefCell>,
}
impl MockMessenger {
fn new() -> Self {
MockMessenger {
sent_messages: RefCell::new(Vec::new()),
}
}
}
impl Messenger for MockMessenger {
fn send(&self, msg: &str) {
// 通过RefCell在&self中修改数据!
self.sent_messages.borrow_mut().push(msg.to_string());
}
}
let messenger = MockMessenger::new();
messenger.send("Hello");
messenger.send("World");
println!("发送的消息: {:?}", messenger.sent_messages.borrow());
// ⚠️ 运行时借用规则仍然有效!
// let ref1 = data.borrow_mut();
// let ref2 = data.borrow_mut(); // ❌ 运行时panic! 已有可变借用
// 安全的多次借用
{
let r1 = data.borrow(); // 不可变借用 ✅
let r2 = data.borrow(); // 再来一个 ✅
println!("r1={:?}, r2={:?}", r1, r2);
} // r1, r2离开作用域
{
let mut w = data.borrow_mut(); // 可变借用 ✅
w.push(5);
println!("写入后: {:?}", w);
}
}
✅ 验证通过
use std::ops::Deref;
// 自定义智能指针
struct MyBox(T);
impl MyBox {
fn new(x: T) -> Self {
MyBox(x)
}
}
impl Deref for MyBox {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl Drop for MyBox {
fn drop(&mut self) {
println!("MyBox被drop! 值被释放");
}
}
fn hello(name: &str) {
println!("你好, {}!", name);
}
fn main() {
let x = MyBox::new(5);
println!("x = {}", *x); // Deref强制转换
let name = MyBox::new(String::from("Rust"));
hello(&name); // Deref: &MyBox → &String → &str
// Drop自动调用
{
let _b = MyBox::new("临时值");
println!("作用域内");
} // Drop在这里自动调用
println!("作用域外");
}
✅ 验证通过
use std::rc::{Rc, Weak};
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
children: RefCell>>,
parent: RefCell
✅ 验证通过
用Box实现二叉搜索树,支持insert、search、inorder遍历。
用Rc<RefCell<T>>和Weak<T>实现双向链表,支持push/pop/遍历。
用Rc<RefCell<HashMap>>实现共享可变缓存,多个模块可以读写同一缓存。
🔒 下一课解锁:闭包与迭代器 —— Rust的函数式编程
| 场景 | 选择 | 原因 |
|---|---|---|
| 递归类型/不确定大小 | Box<T> | 固定大小指针 |
| 多所有者(单线程) | Rc<T> | 引用计数 |
| 多所有者(多线程) | Arc<T> | 原子引用计数 |
| 内部可变性(单线程) | RefCell<T> | 运行时借用检查 |
| 内部可变性(多线程) | Mutex<T> | 锁保护 |
| 共享可变状态 | Rc<RefCell<T>> | 引用计数+内部可变 |
| 线程安全共享可变 | Arc<Mutex<T>> | 最常用的并发模式 |
| 弱引用(防循环) | Weak<T> | 不增加引用计数 |
use std::rc::{Rc, Weak};
use std::cell::RefCell;
fn main() {
// Rc> 模式
let shared_list = Rc::new(RefCell::new(vec![1, 2, 3]));
let list1 = Rc::clone(&shared_list);
list1.borrow_mut().push(4);
let list2 = Rc::clone(&shared_list);
list2.borrow_mut().push(5);
println!("共享列表: {:?}", shared_list.borrow());
println!("引用计数: {}", Rc::strong_count(&shared_list));
// Weak引用防止循环
let strong = Rc::new(42);
let weak: Weak = Rc::downgrade(&strong);
println!("强引用: {}, 弱引用: {}", Rc::strong_count(&strong), Rc::weak_count(&strong));
println!("弱引用升级: {:?}", weak.upgrade());
drop(strong);
println!("释放后弱引用: {:?}", weak.upgrade()); // None
}
✅ 验证通过