智能指针 Box/Rc/Arc
学习目标
- 理解
Box<T> 堆分配
- 理解
Rc<T> 引用计数
- 理解
Arc<T> 原子引用计数
- 掌握使用场景
核心概念
Box<T>
fn main() {
let b = Box::new(5);
println!("b = {}", b);
enum List<T> {
Cons(T, Box<List<T>>),
Nil,
}
use List::{Cons, Nil};
let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));
let large_array = Box::new([0u8; 1_000_000]);
}
Rc<T>(单线程引用计数)
use std::rc::Rc;
fn main() {
let a = Rc::new(5);
let b = Rc::clone(&a);
let c = Rc::clone(&a);
println!("引用计数: {}", Rc::strong_count(&a));
println!("值: {}", *a);
let shared = Rc::new(String::from("hello"));
let s1 = Rc::clone(&shared);
let s2 = Rc::clone(&shared);
println!("{} {} {}", shared, s1, s2);
}
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 = Arc::clone(&data);
let handle = thread::spawn(move || {
println!("线程 {}: {:?}", i, data);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
Rc vs Arc
| 类型 | 线程安全 | 性能 | 使用场景 |
|---|
Rc<T> | 否 | 快 | 单线程共享 |
Arc<T> | 是 | 略慢 | 多线程共享 |
共享图结构
use std::rc::Rc;
#[derive(Debug)]
struct Node {
value: i32,
neighbors: Vec<Rc<Node>>,
}
fn main() {
let node1 = Rc::new(Node { value: 1, neighbors: vec![] });
let node2 = Rc::new(Node { value: 2, neighbors: vec![Rc::clone(&node1)] });
let node3 = Rc::new(Node { value: 3, neighbors: vec![Rc::clone(&node1)] });
println!("node1 引用计数: {}", Rc::strong_count(&node1));
}
实践练习
练习 1:共享配置
use std::rc::Rc;
struct Config {
database_url: String,
max_connections: u32,
}
struct Service {
name: String,
config: Rc<Config>,
}
impl Service {
fn new(name: &str, config: Rc<Config>) -> Self {
Service { name: String::from(name), config }
}
fn info(&self) {
println!("{}: {} (max: {})", self.name, self.config.database_url, self.config.max_connections);
}
}
fn main() {
let config = Rc::new(Config {
database_url: String::from("postgres://localhost/mydb"),
max_connections: 10,
});
let svc1 = Service::new("API", Rc::clone(&config));
let svc2 = Service::new("Worker", Rc::clone(&config));
svc1.info();
svc2.info();
}
常见错误
1. 循环引用
use std::rc::Rc;
use std::cell::RefCell;
2. Rc 用于多线程
let data = Arc::new(5);
小结
| 类型 | 场景 |
|---|
Box<T> | 堆分配,单一所有者 |
Rc<T> | 单线程多所有者 |
Arc<T> | 多线程多所有者 |
Weak<T> | 弱引用,避免循环 |