Rc 智能指针
Rc<T>(Reference Counted)是一个引用计数智能指针,允许多个所有者共享同一份数据。它只能在单线程环境中使用。
什么是 Rc?
Rc<T> 是一个智能指针,它:
- 允许多个所有者共享数据
- 使用引用计数跟踪所有者数量
- 只能在单线程中使用
- 数据是不可变的(除非配合 RefCell)
基本用法
创建和克隆 Rc
use std::rc::Rc;
fn main() {
// 创建 Rc
let data = Rc::new(String::from("Hello, Rc!"));
println!("引用计数: {}", Rc::strong_count(&data));
// 克隆 Rc(增加引用计数)
let data2 = Rc::clone(&data);
let data3 = data.clone(); // 等价写法
println!("引用计数: {}", Rc::strong_count(&data));
println!("data: {}", data);
println!("data2: {}", data2);
println!("data3: {}", data3);
// 检查是否指向同一数据
println!("data 和 data2 相等: {}", Rc::ptr_eq(&data, &data2));
}
引用计数管理
use std::rc::Rc;
fn main() {
let data = Rc::new(vec![1, 2, 3, 4, 5]);
println!("初始引用计数: {}", Rc::strong_count(&data));
{
let data2 = Rc::clone(&data);
println!("克隆后引用计数: {}", Rc::strong_count(&data));
{
let data3 = Rc::clone(&data);
println!("再次克隆后引用计数: {}", Rc::strong_count(&data));
} // data3 离开作用域
println!("data3 离开后引用计数: {}", Rc::strong_count(&data));
} // data2 离开作用域
println!("最终引用计数: {}", Rc::strong_count(&data));
} // data 离开作用域,数据被释放
使用场景
1. 共享数据结构
use std::rc::Rc;
#[derive(Debug)]
struct Node {
value: i32,
children: Vec<Rc<Node>>,
}
impl Node {
fn new(value: i32) -> Rc<Self> {
Rc::new(Node {
value,
children: Vec::new(),
})
}
}
fn main() {
let leaf1 = Node::new(1);
let leaf2 = Node::new(2);
let branch = Rc::new(Node {
value: 10,
children: vec![Rc::clone(&leaf1), Rc::clone(&leaf2)],
});
let root = Rc::new(Node {
value: 100,
children: vec![Rc::clone(&branch), Rc::clone(&leaf1)],
});
println!("树结构: {:#?}", root);
println!("leaf1 引用计数: {}", Rc::strong_count(&leaf1)); // 2
println!("branch 引用计数: {}", Rc::strong_count(&branch)); // 1
}
2. 图数据结构
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct GraphNode {
value: i32,
neighbors: RefCell<Vec<Rc<GraphNode>>>,
}
impl GraphNode {
fn new(value: i32) -> Rc<Self> {
Rc::new(GraphNode {
value,
neighbors: RefCell::new(Vec::new()),
})
}
fn add_neighbor(&self, neighbor: Rc<GraphNode>) {
self.neighbors.borrow_mut().push(neighbor);
}
fn get_neighbors(&self) -> Vec<Rc<GraphNode>> {
self.neighbors.borrow().clone()
}
}
fn main() {
let node1 = GraphNode::new(1);
let node2 = GraphNode::new(2);
let node3 = GraphNode::new(3);
// 创建图的连接
node1.add_neighbor(Rc::clone(&node2));
node1.add_neighbor(Rc::clone(&node3));
node2.add_neighbor(Rc::clone(&node3));
node3.add_neighbor(Rc::clone(&node1));
println!("节点1的邻居数量: {}", node1.get_neighbors().len());
println!("节点1引用计数: {}", Rc::strong_count(&node1)); // 2 (node3 引用了它)
}
3. 缓存系统
use std::rc::Rc;
use std::cell::RefCell;
use std::collections::HashMap;
#[derive(Debug, Clone)]
struct CacheEntry {
key: String,
value: String,
access_count: RefCell<usize>,
}
impl CacheEntry {
fn new(key: String, value: String) -> Self {
CacheEntry {
key,
value,
access_count: RefCell::new(0),
}
}
fn access(&self) -> &str {
*self.access_count.borrow_mut() += 1;
&self.value
}
fn get_access_count(&self) -> usize {
*self.access_count.borrow()
}
}
struct Cache {
entries: HashMap<String, Rc<CacheEntry>>,
}
impl Cache {
fn new() -> Self {
Cache {
entries: HashMap::new(),
}
}
fn insert(&mut self, key: String, value: String) -> Rc<CacheEntry> {
let entry = Rc::new(CacheEntry::new(key.clone(), value));
self.entries.insert(key, Rc::clone(&entry));
entry
}
fn get(&self, key: &str) -> Option<Rc<CacheEntry>> {
self.entries.get(key).cloned()
}
fn stats(&self) {
for (key, entry) in &self.entries {
println!("键: {}, 访问次数: {}, 引用计数: {}",
key, entry.get_access_count(), Rc::strong_count(entry));
}
}
}
fn main() {
let mut cache = Cache::new();
// 插入缓存项
let entry1 = cache.insert("user:123".to_string(), "Alice".to_string());
let entry2 = cache.insert("user:456".to_string(), "Bob".to_string());
// 获取并使用缓存项
if let Some(user) = cache.get("user:123") {
println!("用户: {}", user.access());
println!("用户: {}", user.access());
}
// 创建额外的引用
let user_ref = cache.get("user:123").unwrap();
println!("用户引用: {}", user_ref.access());
cache.stats();
}
Rc 与 RefCell 结合
内部可变性
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Counter {
value: RefCell<i32>,
}
impl Counter {
fn new(initial: i32) -> Rc<Self> {
Rc::new(Counter {
value: RefCell::new(initial),
})
}
fn increment(&self) {
*self.value.borrow_mut() += 1;
}
fn get(&self) -> i32 {
*self.value.borrow()
}
}
fn main() {
let counter = Counter::new(0);
let counter2 = Rc::clone(&counter);
let counter3 = Rc::clone(&counter);
counter.increment();
counter2.increment();
counter3.increment();
println!("计数器值: {}", counter.get()); // 3
println!("引用计数: {}", Rc::strong_count(&counter)); // 3
}
共享可变状态
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct SharedList {
items: RefCell<Vec<String>>,
}
impl SharedList {
fn new() -> Rc<Self> {
Rc::new(SharedList {
items: RefCell::new(Vec::new()),
})
}
fn add(&self, item: String) {
self.items.borrow_mut().push(item);
}
fn get_all(&self) -> Vec<String> {
self.items.borrow().clone()
}
fn len(&self) -> usize {
self.items.borrow().len()
}
}
fn process_list(list: Rc<SharedList>, prefix: &str) {
for i in 1..=3 {
list.add(format!("{}-{}", prefix, i));
}
}
fn main() {
let shared_list = SharedList::new();
// 多个函数共享同一个列表
process_list(Rc::clone(&shared_list), "A");
process_list(Rc::clone(&shared_list), "B");
println!("列表内容: {:?}", shared_list.get_all());
println!("列表长度: {}", shared_list.len());
println!("引用计数: {}", Rc::strong_count(&shared_list));
}
循环引用问题
问题演示
use std::rc::Rc;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Option<Rc<Node>>>,
children: RefCell<Vec<Rc<Node>>>,
}
impl Node {
fn new(value: i32) -> Rc<Self> {
Rc::new(Node {
value,
parent: RefCell::new(None),
children: RefCell::new(Vec::new()),
})
}
fn add_child(&self, child: Rc<Node>) {
child.parent.borrow_mut().replace(Rc::new(Node {
value: self.value,
parent: RefCell::new(None),
children: RefCell::new(Vec::new()),
}));
self.children.borrow_mut().push(child);
}
}
fn demonstrate_cycle_problem() {
let parent = Node::new(1);
let child = Node::new(2);
// 这会创建循环引用!
// parent.add_child(Rc::clone(&child));
println!("演示循环引用问题");
// 内存泄漏:parent 引用 child,child 引用 parent
}
使用 Weak 解决循环引用
use std::rc::{Rc, Weak};
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
value: i32,
parent: RefCell<Option<Weak<Node>>>, // 使用 Weak 避免循环引用
children: RefCell<Vec<Rc<Node>>>,
}
impl Node {
fn new(value: i32) -> Rc<Self> {
Rc::new(Node {
value,
parent: RefCell::new(None),
children: RefCell::new(Vec::new()),
})
}
fn add_child(parent: &Rc<Node>, child: Rc<Node>) {
child.parent.borrow_mut().replace(Rc::downgrade(parent));
parent.children.borrow_mut().push(child);
}
fn get_parent(&self) -> Option<Rc<Node>> {
self.parent.borrow().as_ref()?.upgrade()
}
}
fn main() {
let parent = Node::new(1);
let child1 = Node::new(2);
let child2 = Node::new(3);
Node::add_child(&parent, Rc::clone(&child1));
Node::add_child(&parent, Rc::clone(&child2));
println!("父节点值: {}", parent.value);
println!("子节点数量: {}", parent.children.borrow().len());
if let Some(parent_ref) = child1.get_parent() {
println!("child1 的父节点值: {}", parent_ref.value);
}
println!("parent 强引用计数: {}", Rc::strong_count(&parent));
println!("parent 弱引用计数: {}", Rc::weak_count(&parent));
}
性能考虑
引用计数开销
use std::rc::Rc;
use std::time::Instant;
fn main() {
let n = 1_000_000;
// 测试 Rc 克隆性能
let data = Rc::new(vec![1, 2, 3, 4, 5]);
let start = Instant::now();
let mut refs = Vec::new();
for _ in 0..n {
refs.push(Rc::clone(&data));
}
println!("Rc 克隆时间: {:?}", start.elapsed());
println!("最终引用计数: {}", Rc::strong_count(&data));
// 清理
let start = Instant::now();
refs.clear();
println!("清理时间: {:?}", start.elapsed());
}
内存使用比较
use std::rc::Rc;
use std::mem;
fn main() {
let data = vec![1, 2, 3, 4, 5];
let rc_data = Rc::new(data.clone());
println!("Vec 大小: {} bytes", mem::size_of_val(&data));
println!("Rc 大小: {} bytes", mem::size_of_val(&rc_data));
println!("Rc 指针大小: {} bytes", mem::size_of::<Rc<Vec<i32>>>());
// Rc 的额外开销
println!("引用计数开销: 每个 Rc 实例 {} bytes",
mem::size_of::<Rc<Vec<i32>>>());
}
实际应用示例
观察者模式
use std::rc::Rc;
use std::cell::RefCell;
trait Observer {
fn update(&self, message: &str);
}
struct ConcreteObserver {
name: String,
}
impl ConcreteObserver {
fn new(name: String) -> Self {
ConcreteObserver { name }
}
}
impl Observer for ConcreteObserver {
fn update(&self, message: &str) {
println!("{} 收到消息: {}", self.name, message);
}
}
struct Subject {
observers: RefCell<Vec<Rc<dyn Observer>>>,
}
impl Subject {
fn new() -> Self {
Subject {
observers: RefCell::new(Vec::new()),
}
}
fn attach(&self, observer: Rc<dyn Observer>) {
self.observers.borrow_mut().push(observer);
}
fn notify(&self, message: &str) {
for observer in self.observers.borrow().iter() {
observer.update(message);
}
}
}
fn main() {
let subject = Subject::new();
let observer1: Rc<dyn Observer> = Rc::new(ConcreteObserver::new("观察者1".to_string()));
let observer2: Rc<dyn Observer> = Rc::new(ConcreteObserver::new("观察者2".to_string()));
subject.attach(Rc::clone(&observer1));
subject.attach(Rc::clone(&observer2));
subject.notify("重要通知!");
println!("observer1 引用计数: {}", Rc::strong_count(&observer1));
}
最佳实践
1. 何时使用 Rc
// 适合使用 Rc 的场景:
// - 需要多个所有者共享数据
// - 单线程环境
// - 数据结构如树、图
// - 缓存系统
// 不适合的场景:
// - 多线程环境(使用 Arc)
// - 需要可变性(配合 RefCell)
// - 简单的单一所有权(使用 Box)
2. 避免循环引用
use std::rc::{Rc, Weak};
// 好的做法:使用 Weak 打破循环
struct Parent {
children: Vec<Rc<Child>>,
}
struct Child {
parent: Weak<Parent>, // 使用 Weak 引用
}
3. 性能优化
use std::rc::Rc;
fn optimize_rc_usage() {
// 好:重用 Rc
let data = Rc::new(expensive_computation());
let data1 = Rc::clone(&data);
let data2 = Rc::clone(&data);
// 避免:重复计算
// let data1 = Rc::new(expensive_computation());
// let data2 = Rc::new(expensive_computation());
}
fn expensive_computation() -> Vec<i32> {
(0..1000).collect()
}
Rc 是单线程环境下共享所有权的理想选择,但需要注意循环引用问题。下一节我们将学习多线程环境下的 Arc 智能指针。