知识点:Box 回顾 — 堆上分配
// Box<T> 把数据放在堆上,栈上只存指针
// 适用场景:
// 1. 编译时大小未知的类型(如递归类型)
// 2. 大量数据需要转移所有权但不想拷贝
// 3. 只关心值是否实现了某个 trait(trait 对象)
// 递归类型必须用 Box
#[derive(Debug)]
enum List {
Cons(i32, Box<List>), // Box 让编译器知道大小
Nil,
}
fn build_list() -> List {
List::Cons(1, Box::new(
List::Cons(2, Box::new(
List::Cons(3, Box::new(
List::Nil
))
))
))
}
fn print_list(list: &List) {
match list {
List::Cons(val, next) => {
print!("{} ", val);
print_list(next);
}
List::Nil => println!("Nil"),
}
}
// Box 实现 Deref,可以像普通引用一样使用
fn deref_example() {
let b = Box::new(5);
println!("值: {}", *b); // 自动解引用
println!("值: {}", b); // Display 也会自动解引用
}
// Box 实现 Drop,离开作用域自动释放堆内存
fn drop_example() {
{
let b = Box::new(String::from("hello"));
println!("{}", b);
} // b 离开作用域,堆上的 String 被释放
}
fn main() {
let list = build_list();
print_list(&list); // 1 2 3 Nil
deref_example();
drop_example();
}
知识点:Rc — 引用计数(单线程共享所有权)
use std::rc::Rc;
// Rc<T> 允许多个所有者共享同一份数据
// 引用计数:每多一个 Rc 指向数据,计数+1
// 当计数归零时,数据被释放
// ⚠️ 只能用于单线程!多线程用 Arc<T>
#[derive(Debug)]
struct SharedData {
value: String,
}
fn rc_basics() {
let data = Rc::new(SharedData {
value: String::from("共享数据"),
});
println!("引用计数: {}", Rc::strong_count(&data)); // 1
let clone1 = Rc::clone(&data); // 计数+1(不是深拷贝!)
println!("引用计数: {}", Rc::strong_count(&data)); // 2
let clone2 = Rc::clone(&data); // 计数+1
println!("引用计数: {}", Rc::strong_count(&data)); // 3
// 多个 Rc 指向同一份数据
println!("data: {}", data.value);
println!("clone1: {}", clone1.value);
println!("clone2: {}", clone2.value);
// 验证是同一份数据(比较指针地址)
println!("同一数据? {}", Rc::ptr_eq(&data, &clone1)); // true
drop(clone2);
println!("drop clone2 后计数: {}", Rc::strong_count(&data)); // 2
drop(clone1);
println!("drop clone1 后计数: {}", Rc::strong_count(&data)); // 1
}
// 实际场景:多个结构体共享同一份数据
#[derive(Debug)]
struct Node {
value: i32,
parent: Rc<Node>, // 共享父节点
}
fn shared_parent() {
let root = Rc::new(Node { value: 0, parent: Rc::new(Node { value: –1, parent: Rc::new(Node { value: –1, parent: unsafe { Rc::from_raw(std::ptr::null()) } }) }) });
// 上面的写法太复杂,实际中用 RefCell 或 Option
// 更好的方式
let root = Rc::new(Node2 { value: 0, children: vec![] });
// … 见后面 RefCell 的例子
}
// 简单示例:共享配置
#[derive(Debug)]
struct Config {
db_host: String,
max_connections: u32,
}
#[derive(Debug)]
struct Service {
name: String,
config: Rc<Config>, // 共享配置
}
fn shared_config() {
let config = Rc::new(Config {
db_host: String::from("localhost"),
max_connections: 100,
});
let services = vec![
Service { name: String::from("用户服务"), config: Rc::clone(&config) },
Service { name: String::from("订单服务"), config: Rc::clone(&config) },
Service { name: String::from("支付服务"), config: Rc::clone(&config) },
];
for svc in &services {
println!("{}: db={}, max_conn={}", svc.name, svc.config.db_host, svc.config.max_connections);
}
println!("配置引用计数: {}", Rc::strong_count(&config)); // 4(3个service + 1个原始)
}
fn main() {
rc_basics();
println!("—");
shared_config();
}
知识点:RefCell — 内部可变性
use std::cell::RefCell;
// RefCell<T> 允许在不可变引用下修改数据
// 把借用检查从编译期推迟到运行期
// 违反借用规则时会 panic(而非编译错误)
fn refcell_basics() {
let data = RefCell::new(vec![1, 2, 3]);
// borrow():不可变借用(可以多个)
println!("数据: {:?}", data.borrow());
// borrow_mut():可变借用(只能一个,且不能和 borrow 共存)
data.borrow_mut().push(4);
println!("修改后: {:?}", data.borrow());
// 运行期检查:违反规则会 panic
// let r1 = data.borrow();
// let r2 = data.borrow_mut(); // ❌ panic! 同时有不可变和可变借用
}
// 运行期借用检查 vs 编译期借用检查
fn comparison() {
// 编译期检查(普通引用)
let mut v = vec![1, 2, 3];
let r1 = &v;
// let r2 = &mut v; // ❌ 编译错误!
println!("{}", r1[0]);
// 运行期检查(RefCell)
let cell = RefCell::new(vec![1, 2, 3]);
let r1 = cell.borrow();
// let r2 = cell.borrow_mut(); // ❌ 运行时 panic!
println!("{}", r1[0]);
// 区别:RefCell 的代码能编译通过,但在运行时 panic
}
// RefCell 的实际用途:在只能获取不可变引用的地方修改数据
// 例如:回调函数、缓存、计数器
#[derive(Debug)]
struct Cache {
data: RefCell<std::collections::HashMap<String, String>>,
}
impl Cache {
fn new() -> Self {
Cache {
data: RefCell::new(std::collections::HashMap::new()),
}
}
// &self 而不是 &mut self!
// 因为内部用 RefCell 实现了可变性
fn get_or_insert(&self, key: &str, value: &str) -> String {
let mut cache = self.data.borrow_mut();
if let Some(v) = cache.get(key) {
v.clone()
} else {
cache.insert(key.to_string(), value.to_string());
value.to_string()
}
}
fn len(&self) -> usize {
self.data.borrow().len()
}
}
fn cache_example() {
let cache = Cache::new(); // 注意:不是 mut!
// 通过不可变引用调用"修改"方法
let val1 = cache.get_or_insert("key1", "value1");
let val2 = cache.get_or_insert("key1", "value2"); // 已存在,返回 value1
let val3 = cache.get_or_insert("key2", "value3");
println!("val1: {}", val1); // value1
println!("val2: {}", val2); // value1(缓存命中)
println!("val3: {}", val3); // value3
println!("缓存大小: {}", cache.len()); // 2
}
fn main() {
refcell_basics();
println!("—");
cache_example();
}
知识点:Rc> — 共享 + 可变
use std::rc::Rc;
use std::cell::RefCell;
// Rc 提供共享所有权
// RefCell 提供内部可变性
// 组合起来 = 多个所有者 + 可修改
#[derive(Debug)]
struct TreeNode {
value: String,
children: RefCell<Vec<Rc<TreeNode>>>,
}
impl TreeNode {
fn new(value: &str) -> Rc<Self> {
Rc::new(TreeNode {
value: value.to_string(),
children: RefCell::new(vec![]),
})
}
fn add_child(parent: &Rc<TreeNode>, child: Rc<TreeNode>) {
parent.children.borrow_mut().push(child);
}
fn print_tree(node: &Rc<TreeNode>, indent: usize) {
println!("{}{}", " ".repeat(indent), node.value);
for child in node.children.borrow().iter() {
TreeNode::print_tree(child, indent + 2);
}
}
}
fn tree_example() {
let root = TreeNode::new("根节点");
let child1 = TreeNode::new("子节点1");
let child2 = TreeNode::new("子节点2");
let grandchild = TreeNode::new("孙节点1");
TreeNode::add_child(&root, child1.clone());
TreeNode::add_child(&root, child2.clone());
TreeNode::add_child(&child1, grandchild.clone());
TreeNode::print_tree(&root, 0);
// 根节点
// 子节点1
// 孙节点1
// 子节点2
}
// 实际场景:事件系统
#[derive(Debug)]
struct EventBus {
listeners: RefCell<Vec<Box<dyn Fn(&str)>>>,
}
impl EventBus {
fn new() -> Self {
EventBus {
listeners: RefCell::new(vec![]),
}
}
fn subscribe(&self, callback: Box<dyn Fn(&str)>) {
self.listeners.borrow_mut().push(callback);
}
fn emit(&self, event: &str) {
for listener in self.listeners.borrow().iter() {
listener(event);
}
}
}
fn event_example() {
let bus = EventBus::new();
bus.subscribe(Box::new(|e| println!("监听器1收到: {}", e)));
bus.subscribe(Box::new(|e| println!("监听器2收到: {}", e)));
bus.emit("用户登录");
bus.emit("数据更新");
}
fn main() {
tree_example();
println!("—");
event_example();
}
知识点:Cell — 用于 Copy 类型
use std::cell::Cell;
// Cell<T> 是 RefCell<T> 的简化版
// 适用于 T: Copy 的类型(如 i32, f64, bool)
// 不需要 borrow/borrow_mut,直接用 get/set
// 性能更好(没有运行期借用检查开销)
fn cell_basics() {
let counter = Cell::new(0);
// get():复制出值
println!("当前值: {}", counter.get()); // 0
// set():直接设置新值
counter.set(10);
println!("设置后: {}", counter.get()); // 10
// replace():设置新值并返回旧值
let old = counter.replace(20);
println!("旧值: {}, 新值: {}", old, counter.get()); // 10, 20
// 常用方法
counter.set(counter.get() + 1);
println!("加1后: {}", counter.get()); // 21
}
// 实际场景:不可变结构体中的计数器
#[derive(Debug)]
struct RequestCounter {
name: String,
count: Cell<u64>, // 内部可变,但结构体不需要 mut
}
impl RequestCounter {
fn new(name: &str) -> Self {
RequestCounter {
name: name.to_string(),
count: Cell::new(0),
}
}
// &self 而非 &mut self
fn record_request(&self) {
self.count.set(self.count.get() + 1);
}
fn get_count(&self) -> u64 {
self.count.get()
}
}
fn counter_example() {
let counter = RequestCounter::new("API");
// 不需要 mut!
counter.record_request();
counter.record_request();
counter.record_request();
println!("{} 请求次数: {}", counter.name, counter.get_count()); // 3
}
// Cell 的常见模式:用 update_with 简化
fn cell_update() {
let val = Cell::new(10);
// 常见操作:读取 -> 修改 -> 写回
val.set(val.get() * 2);
println!("翻倍: {}", val.get()); // 20
val.set(val.get() + 5);
println!("加5: {}", val.get()); // 25
}
fn main() {
cell_basics();
println!("—");
counter_example();
println!("—");
cell_update();
}
知识点:Weak — 弱引用(打破循环引用)
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
// Weak<T> 类似 Rc<T>,但不增加强引用计数
// 不会阻止数据被释放
// 用 upgrade() 尝试获取 Rc<T>(可能返回 None)
// 循环引用问题:
// A -> B -> A 会导致引用计数永远不归零,内存泄漏
#[derive(Debug)]
struct Node {
value: i32,
next: RefCell<Option<Rc<Node>>>,
prev: RefCell<Option<Weak<Node>>>, // 用 Weak 打破循环!
}
impl Node {
fn new(value: i32) -> Rc<Self> {
Rc::new(Node {
value,
next: RefCell::new(None),
prev: RefCell::new(None),
})
}
}
fn doubly_linked_list() {
let node1 = Node::new(1);
let node2 = Node::new(2);
let node3 = Node::new(3);
// 1 -> 2 -> 3
*node1.next.borrow_mut() = Some(Rc::clone(&node2));
*node2.next.borrow_mut() = Some(Rc::clone(&node3));
// 3 -> 2 -> 1(用 Weak 避免循环引用)
*node3.prev.borrow_mut() = Some(Rc::downgrade(&node2));
*node2.prev.borrow_mut() = Some(Rc::downgrade(&node1));
// 正向遍历
print!("正向: ");
let mut current = Some(Rc::clone(&node1));
while let Some(node) = current {
print!("{} ", node.value);
current = node.next.borrow().clone();
}
println!();
// 反向遍历
print!("反向: ");
let mut current = Some(Rc::clone(&node3));
while let Some(node) = current {
print!("{} ", node.value);
current = node.prev.borrow().as_ref()
.and_then(|weak| weak.upgrade());
}
println!();
// 验证引用计数
println!("node1 强引用: {}, 弱引用: {}",
Rc::strong_count(&node1),
Rc::weak_count(&node1));
println!("node2 强引用: {}, 弱引用: {}",
Rc::strong_count(&node2),
Rc::weak_count(&node2));
}
// Weak 的实际用途:缓存
use std::collections::HashMap;
struct ImageCache {
cache: RefCell<HashMap<String, Weak<Vec<u8>>>>,
}
impl ImageCache {
fn new() -> Self {
ImageCache {
cache: RefCell::new(HashMap::new()),
}
}
fn get(&self, key: &str) -> Option<Rc<Vec<u8>>> {
let cache = self.cache.borrow();
cache.get(key).and_then(|weak| {
weak.upgrade() // 如果数据还在,返回 Some(Rc)
// 如果已被释放,返回 None
})
}
fn insert(&self, key: String, data: Rc<Vec<u8>>) {
let weak = Rc::downgrade(&data);
self.cache.borrow_mut().insert(key, weak);
}
fn cleanup(&self) {
// 移除已失效的弱引用
self.cache.borrow_mut().retain(|_, weak| weak.strong_count() > 0);
}
}
fn cache_example() {
let cache = ImageCache::new();
// 插入一些数据
let img1 = Rc::new(vec![1, 2, 3]);
let img2 = Rc::new(vec![4, 5, 6]);
cache.insert("img1.png".into(), img1.clone());
cache.insert("img2.png".into(), img2.clone());
// 能获取到
println!("img1: {:?}", cache.get("img1.png").map(|d| d.len()));
println!("img2: {:?}", cache.get("img2.png").map(|d| d.len()));
// 释放 img1 的强引用
drop(img1);
// img1 已被释放,获取返回 None
println!("img1 (已释放): {:?}", cache.get("img1.png"));
println!("img2 (仍在): {:?}", cache.get("img2.png"));
// 清理失效的弱引用
cache.cleanup();
}
fn main() {
doubly_linked_list();
println!("—");
cache_example();
}
知识点:各种智能指针与内部可变性类型对比
// === 所有权模型对比 ===
// 单一所有权:
// Box<T> — 堆上分配,单一所有者
// String — 堆上字符串,单一所有者
// Vec<T> — 堆上数组,单一所有者
// 共享所有权(不可变):
// Rc<T> — 单线程引用计数
// Arc<T> — 多线程引用计数(原子操作)
// 内部可变性(单线程):
// Cell<T> — 用于 Copy 类型,无运行期检查
// RefCell<T> — 用于任意类型,运行期借用检查
// UnsafeCell<T> — 最底层,无检查(unsafe)
// 共享 + 可变(单线程):
// Rc<RefCell<T>> — 多个所有者 + 可修改
// Rc<Cell<T>> — 多个所有者 + 可修改(Copy类型)
// 共享 + 可变(多线程):
// Arc<Mutex<T>> — 多个所有者 + 互斥修改
// Arc<RwLock<T>> — 多个所有者 + 读写锁
// 弱引用:
// Weak<T> — Rc 的弱引用版本
// Arc 也有 Weak — Arc::downgrade()
fn main() {
println!("智能指针速查:");
println!(" 堆分配: Box<T>");
println!(" 共享(只读): Rc<T> / Arc<T>");
println!(" 内部可变: Cell<T> / RefCell<T>");
println!(" 共享+可变: Rc<RefCell<T>> / Arc<Mutex<T>>");
println!(" 弱引用: Weak<T>");
println!("");
println!("选择指南:");
println!(" 需要堆分配? → Box<T>");
println!(" 需要共享只读? → Rc<T>(单线程)/ Arc<T>(多线程)");
println!(" 需要内部修改? → Cell<T>(Copy类型)/ RefCell<T>(任意类型)");
println!(" 需要共享+修改? → Rc<RefCell<T>>(单线程)/ Arc<Mutex<T>>(多线程)");
println!(" 避免循环引用? → Weak<T>");
}
核心规则
类型 所有权 可变性 线程安全 开销
Box 单一 需 mut ✅ 最低
Rc 共享 不可变 ❌ 低(计数)
Arc 共享 不可变 ✅ 中(原子计数)
Cell 单一 内部可变 ❌ 最低(Copy)
RefCell 单一 内部可变 ❌ 中(运行期检查)
Rc<RefCell> 共享 内部可变 ❌ 中+中
Arc<Mutex> 共享 内部可变 ✅ 高(原子+锁)
Weak 不拥有 — 跟随 Rc/Arc 低
动手试试
补全下面的代码:
use std::rc::Rc;
use std::cell::RefCell;
use std::cell::Cell;
use std::collections::HashMap;
// === 题目1:任务管理器 ===
// 补全:实现 TaskManager,使用内部可变性
// – tasks 字段用 RefCell<Vec<String>> 存储
// – completed_count 字段用 Cell<u32> 统计完成数
// – add_task(&self, task: &str):添加任务
// – complete_task(&self, index: usize) -> bool:
// 如果 index 有效,移除该任务并增加 completed_count,返回 true
// 如果 index 无效,返回 false
// – pending_count(&self) -> usize:返回待完成任务数
// – total_completed(&self) -> u32:返回已完成总数
struct TaskManager {
// 补全字段
}
impl TaskManager {
fn new() -> Self {
// 补全
todo!()
}
fn add_task(&self, task: &str) {
// 补全
todo!()
}
fn complete_task(&self, index: usize) -> bool {
// 补全
todo!()
}
fn pending_count(&self) -> usize {
// 补全
todo!()
}
fn total_completed(&self) -> u32 {
// 补全
todo!()
}
}
// === 题目2:共享配置 + 统计 ===
// 补全:实现 SharedConfig
// – 用 Rc 共享配置数据
// – 用 Cell 记录访问次数
// – get(&self, key: &str) -> Option<String>:获取配置值,增加访问计数
// – access_count(&self) -> u64:返回访问次数
struct SharedConfig {
data: Rc<HashMap<String, String>>,
access_count: Cell<u64>,
}
impl SharedConfig {
fn new() -> Self {
// 补全:创建一个空的 SharedConfig
todo!()
}
fn with_data(data: HashMap<String, String>) -> Self {
// 补全:用给定的数据创建 SharedConfig
todo!()
}
fn get(&self, key: &str) -> Option<String> {
// 补全:查找 key,如果找到则增加访问计数并返回 Some(value)
todo!()
}
fn access_count(&self) -> u64 {
// 补全
todo!()
}
fn clone_ref(&self) -> Self {
// 补全:克隆 Rc(共享数据),但 access_count 重置为 0
todo!()
}
}
// === 题目3:树结构 + 父节点弱引用 ===
// 补全:实现带父节点引用的树节点
struct TreeNode {
value: String,
children: RefCell<Vec<Rc<TreeNode>>>,
parent: RefCell<Option<std::rc::Weak<TreeNode>>>, // 弱引用
}
impl TreeNode {
fn new(value: &str) -> Rc<Self> {
// 补全
todo!()
}
fn add_child(parent: &Rc<TreeNode>, child: Rc<TreeNode>) {
// 补全:添加子节点,并设置子节点的 parent 为 parent 的弱引用
todo!()
}
fn get_parent_value(node: &Rc<TreeNode>) -> Option<String> {
// 补全:获取父节点的值(通过弱引用的 upgrade)
todo!()
}
fn get_root(node: &Rc<TreeNode>) -> Rc<TreeNode> {
// 补全:向上遍历找到根节点
todo!()
}
}
impl std::fmt::Debug for TreeNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "TreeNode({})", self.value)
}
}
fn main() {
// === 测试 TaskManager ===
let tm = TaskManager::new();
tm.add_task("写报告");
tm.add_task("开会");
tm.add_task("代码审查");
tm.add_task("修bug");
println!("待完成: {}", tm.pending_count()); // 期望: 4
println!("已完成: {}", tm.total_completed()); // 期望: 0
assert!(tm.complete_task(1)); // 完成"开会"
assert!(tm.complete_task(0)); // 完成"写报告"(原index 0,因为"开会"被移除后"写报告"变成了index 0)
assert!(!tm.complete_task(10)); // 无效索引
println!("待完成: {}", tm.pending_count()); // 期望: 2
println!("已完成: {}", tm.total_completed()); // 期望: 2
// === 测试 SharedConfig ===
let mut data = HashMap::new();
data.insert("host".into(), "localhost".into());
data.insert("port".into(), "5432".into());
data.insert("db".into(), "mydb".into());
let config = SharedConfig::with_data(data);
let config2 = config.clone_ref();
println!("host: {:?}", config.get("host")); // Some("localhost")
println!("port: {:?}", config.get("port")); // Some("5432")
println!("missing: {:?}", config.get("missing")); // None
println!("config 访问次数: {}", config.access_count()); // 期望: 2
println!("config2 访问次数: {}", config2.access_count()); // 期望: 0(独立的计数)
// === 测试 TreeNode ===
let root = TreeNode::new("根");
let child1 = TreeNode::new("子1");
let child2 = TreeNode::new("子2");
let grandchild = TreeNode::new("孙1");
TreeNode::add_child(&root, child1.clone());
TreeNode::add_child(&root, child2.clone());
TreeNode::add_child(&child1, grandchild.clone());
// 测试父节点
println!("child1 的父节点: {:?}", TreeNode::get_parent_value(&child1));
// 期望: Some("根")
println!("grandchild 的父节点: {:?}", TreeNode::get_parent_value(&grandchild));
// 期望: Some("子1")
println!("root 的父节点: {:?}", TreeNode::get_parent_value(&root));
// 期望: None
// 测试找根节点
let found_root = TreeNode::get_root(&grandchild);
println!("grandchild 的根: {:?}", found_root);
// 期望: TreeNode(根)
}
期望输出:
待完成: 4
已完成: 0
待完成: 2
已完成: 2
host: Some(“localhost”)
port: Some(“5432”)
missing: None
config 访问次数: 2
config2 访问次数: 0
child1 的父节点: Some(“根”)
grandchild 的父节点: Some(“子1”)
root 的父节点: None
grandchild 的根: TreeNode(根)
写好了贴过来,没问题就进入第30课:宏 Macros 入门 👋
贴代码
完整参考答案(Rc / RefCell / Cell / Weak 内部可变性经典练习题)
use std::rc::Rc;
use std::cell::RefCell;
use std::cell::Cell;
use std::collections::HashMap;
use std::rc::Weak;
// === 题目1:任务管理器 ===
struct TaskManager {
tasks: RefCell<Vec<String>>,
completed_count: Cell<u32>,
}
impl TaskManager {
fn new() -> Self {
TaskManager {
tasks: RefCell::new(Vec::new()),
completed_count: Cell::new(0),
}
}
fn add_task(&self, task: &str) {
self.tasks.borrow_mut().push(task.to_string());
}
fn complete_task(&self, index: usize) -> bool {
let mut tasks = self.tasks.borrow_mut();
if index >= tasks.len() {
return false;
}
tasks.remove(index);
let cnt = self.completed_count.get();
self.completed_count.set(cnt + 1);
true
}
fn pending_count(&self) -> usize {
self.tasks.borrow().len()
}
fn total_completed(&self) -> u32 {
self.completed_count.get()
}
}
// === 题目2:共享配置 + 统计 ===
struct SharedConfig {
data: Rc<HashMap<String, String>>,
access_count: Cell<u64>,
}
impl SharedConfig {
fn new() -> Self {
SharedConfig {
data: Rc::new(HashMap::new()),
access_count: Cell::new(0),
}
}
fn with_data(data: HashMap<String, String>) -> Self {
SharedConfig {
data: Rc::new(data),
access_count: Cell::new(0),
}
}
fn get(&self, key: &str) -> Option<String> {
// 只要调用get就计数,不管key是否存在,和题目示例输出保持一致
let current = self.access_count.get();
self.access_count.set(current + 1);
self.data.get(key).cloned()
}
fn access_count(&self) -> u64 {
self.access_count.get()
}
fn clone_ref(&self) -> Self {
SharedConfig {
data: Rc::clone(&self.data),
access_count: Cell::new(0),
}
}
}
// === 题目3:树结构 + 父节点弱引用 ===
struct TreeNode {
value: String,
children: RefCell<Vec<Rc<TreeNode>>>,
parent: RefCell<Option<Weak<TreeNode>>>,
}
impl TreeNode {
fn new(value: &str) -> Rc<Self> {
Rc::new(TreeNode {
value: value.to_string(),
children: RefCell::new(Vec::new()),
parent: RefCell::new(None),
})
}
fn add_child(parent: &Rc<TreeNode>, child: Rc<TreeNode>) {
// 子节点存入父节点的children列表
parent.children.borrow_mut().push(child.clone());
// 设置子节点的parent为父节点的弱引用,避免循环引用
let weak_parent = Rc::downgrade(parent);
*child.parent.borrow_mut() = Some(weak_parent);
}
fn get_parent_value(node: &Rc<TreeNode>) -> Option<String> {
let parent_opt = node.parent.borrow();
match &*parent_opt {
Some(weak) => weak.upgrade().map(|p| p.value.clone()),
None => None,
}
}
fn get_root(mut node: &Rc<TreeNode>) -> Rc<TreeNode> {
loop {
let parent_opt = node.parent.borrow();
match &*parent_opt {
Some(weak) => {
let p = weak.upgrade().unwrap();
node = &p;
}
None => break,
}
}
node.clone()
}
}
impl std::fmt::Debug for TreeNode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "TreeNode({})", self.value)
}
}
fn main() {
// === 测试 TaskManager ===
let tm = TaskManager::new();
tm.add_task("写报告");
tm.add_task("开会");
tm.add_task("代码审查");
tm.add_task("修bug");
println!("待完成: {}", tm.pending_count()); // 期望: 4
println!("已完成: {}", tm.total_completed()); // 期望: 0
assert!(tm.complete_task(1)); // 完成"开会"
assert!(tm.complete_task(0)); // 完成"写报告"(原index 0,因为"开会"被移除后"写报告"变成了index 0)
assert!(!tm.complete_task(10)); // 无效索引
println!("待完成: {}", tm.pending_count()); // 期望: 2
println!("已完成: {}", tm.total_completed()); // 期望: 2
// === 测试 SharedConfig ===
let mut data = HashMap::new();
data.insert("host".into(), "localhost".into());
data.insert("port".into(), "5432".into());
data.insert("db".into(), "mydb".into());
let config = SharedConfig::with_data(data);
let config2 = config.clone_ref();
println!("host: {:?}", config.get("host")); // Some("localhost")
println!("port: {:?}", config.get("port")); // Some("5432")
println!("missing: {:?}", config.get("missing")); // None
println!("config 访问次数: {}", config.access_count()); // 期望: 3
println!("config2 访问次数: {}", config2.access_count()); // 期望: 0(独立的计数)
// === 测试 TreeNode ===
let root = TreeNode::new("根");
let child1 = TreeNode::new("子1");
let child2 = TreeNode::new("子2");
let grandchild = TreeNode::new("孙1");
TreeNode::add_child(&root, child1.clone());
TreeNode::add_child(&root, child2.clone());
TreeNode::add_child(&child1, grandchild.clone());
// 测试父节点
println!("child1 的父节点: {:?}", TreeNode::get_parent_value(&child1));
// 期望: Some("根")
println!("grandchild 的父节点: {:?}", TreeNode::get_parent_value(&grandchild));
// 期望: Some("子1")
println!("root 的父节点: {:?}", TreeNode::get_parent_value(&root));
// 期望: None
// 测试找根节点
let found_root = TreeNode::get_root(&grandchild);
println!("grandchild 的根: {:?}", found_root);
// 期望: TreeNode(根)
}
运行输出说明
注意: config.get(“missing”) 这一行也触发一次访问计数,最终 config 的访问次数 =3。
plaintext
待完成: 4
已完成: 0
待完成: 2
已完成: 2
host: Some(“localhost”)
port: Some(“5432”)
missing: None
config 访问次数: 3
config2 访问次数: 0
child1 的父节点: Some(“根”)
grandchild 的父节点: Some(“子1”)
root 的父节点: None
grandchild 的根: TreeNode(根)
核心知识点详解(Rc‑RefCell‑Cell‑Weak)
1. TaskManager(内部可变性)
- RefCell<Vec>:运行时借用检查,不可变的 &self 也可以修改内部数据, borrow() / borrow_mut() ;
- Cell:适合Copy类型(u32,i32,bool),不需要借用, .get() / .set() ,比RefCell轻量,没有运行时开销;
Cell 只能存 Copy,非 Copy 必须用 RefCell。
2. SharedConfig(Rc共享 + Cell独立计数器)
- Rc<HashMap<…>> :多个SharedConfig实例共享同一份哈希表(clone_ref时Rc::clone,引用计数+1,数据不复制);
- access_count是Cell,每一个SharedConfig实例各自一份,clone_ref的时候新建Cell(0),所以config和config2访问计数互相独立;
Rc负责数据共享,Cell负责实例本地可变状态,二者分工明确。
3. TreeNode 树(循环引用解决方案 Rc + Weak)
如果子节点用Rc指向父节点:双向Rc → 循环引用 → 内存泄漏。
解决方法:子存父:Weak;父存子:Rc
3.1 Rc::downgrade(parent) → Weak,弱引用不增加强引用计数;
3.2 weak.upgrade() → Option<Rc>:尝试升级为强引用,如果节点已经释放返回None;
3.3 get_root:循环沿着parent向上遍历,直到父节点为None,就是根。
网硕互联帮助中心

评论前必须登录!
注册