
文章目录
- [第14章 智能指针](#第14章 智能指针)
-
- [14.1 Box<T>堆内存分配](#14.1 Box<T>堆内存分配)
- [14.2 Deref和Drop trait](#14.2 Deref和Drop trait)
-
- [Deref Trait:智能指针的核心](#Deref Trait:智能指针的核心)
-
- 基本Deref实现
- [解引用转换(Deref Coercion)](#解引用转换(Deref Coercion))
- [Drop Trait:资源清理](#Drop Trait:资源清理)
- Deref和Drop的交互
- [14.3 Rc<T>引用计数指针](#14.3 Rc<T>引用计数指针)
- [14.4 RefCell<T>与内部可变性](#14.4 RefCell<T>与内部可变性)
- 总结
第14章 智能指针
智能指针是Rust中管理堆内存和实现复杂所有权模式的核心工具。它们不仅像普通指针一样指向某个内存地址,还拥有额外的元数据和功能,如引用计数、内部可变性等。Rust的智能指针系统建立在所有权和借用规则之上,提供了在编译时和运行时保证内存安全的多种方式。本章将深入探讨各种智能指针的特性和使用场景,从基础的Box<T>到复杂的引用计数和内部可变性模式。
14.1 Box堆内存分配
Box基础与堆内存管理
Box<T>是Rust中最简单的智能指针,它允许将数据存储在堆上而不是栈上。Box在栈中存储一个指向堆数据的指针,当Box离开作用域时,会自动释放其指向的堆内存。
基本使用
rust
fn box_basics() {
// 在栈上分配整数
let stack_value = 42;
println!("Stack value: {}, address: {:p}", stack_value, &stack_value);
// 在堆上分配整数
let heap_value = Box::new(42);
println!("Heap value: {}, address: {:p}", heap_value, heap_value);
println!("Box itself address: {:p}", &heap_value);
// 解引用Box
let actual_value = *heap_value;
println!("Dereferenced value: {}", actual_value);
// Box离开作用域时自动释放内存
{
let temporary_box = Box::new(100);
println!("Temporary value: {}", temporary_box);
// 在这里,temporary_box离开作用域,内存被自动释放
}
// println!("{}", temporary_box); // 编译错误:值已经被移动
// 大型数据结构更适合放在堆上
let large_data = Box::new([0u8; 1_000_000]); // 1MB数组
println!("Large data length: {}", large_data.len());
// 当large_data离开作用域时,1MB内存会被自动释放
}
使用Box的场景
rust
fn box_use_cases() {
// 1. 当有大量数据且不想在栈上拷贝时
let big_data = vec![0u8; 10_000_000]; // 10MB向量
let boxed_big_data = Box::new(big_data);
println!("Boxed big data length: {}", boxed_big_data.len());
// 2. 当拥有一个 trait 对象,但不知道具体类型时
trait Animal {
fn speak(&self);
}
struct Dog;
impl Animal for Dog {
fn speak(&self) {
println!("Woof!");
}
}
struct Cat;
impl Animal for Cat {
fn speak(&self) {
println!("Meow!");
}
}
let animals: Vec<Box<dyn Animal>> = vec![
Box::new(Dog),
Box::new(Cat),
];
for animal in animals {
animal.speak();
}
// 3. 当需要递归数据结构时(见后续示例)
}
递归数据结构与Box
递归数据结构是Box最典型的应用场景,因为Rust需要在编译时知道类型的大小。
rust
// 使用Box实现递归数据结构:链表
#[derive(Debug)]
enum List<T> {
Cons(T, Box<List<T>>),
Nil,
}
impl<T> List<T> {
fn new() -> Self {
List::Nil
}
fn prepend(self, elem: T) -> Self {
List::Cons(elem, Box::new(self))
}
fn len(&self) -> usize {
match self {
List::Cons(_, tail) => 1 + tail.len(),
List::Nil => 0,
}
}
fn is_empty(&self) -> bool {
matches!(self, List::Nil)
}
fn iter(&self) -> ListIter<'_, T> {
ListIter { current: self }
}
}
// 为链表实现迭代器
struct ListIter<'a, T> {
current: &'a List<T>,
}
impl<'a, T> Iterator for ListIter<'a, T> {
type Item = &'a T;
fn next(&mut self) -> Option<Self::Item> {
match self.current {
List::Cons(value, next) => {
self.current = next;
Some(value)
}
List::Nil => None,
}
}
}
fn recursive_data_structures() {
// 创建链表: 1 -> 2 -> 3 -> Nil
let list = List::new()
.prepend(3)
.prepend(2)
.prepend(1);
println!("List: {:?}", list);
println!("List length: {}", list.len());
println!("Is empty: {}", list.is_empty());
// 使用迭代器
println!("List elements:");
for elem in list.iter() {
println!(" {}", elem);
}
// 字符串链表
let string_list = List::new()
.prepend("world")
.prepend("hello");
println!("String list: {:?}", string_list);
// 更复杂的递归结构:二叉树
#[derive(Debug)]
enum BinaryTree<T> {
Node(T, Box<BinaryTree<T>>, Box<BinaryTree<T>>),
Leaf(T),
Empty,
}
impl<T: Ord> BinaryTree<T> {
fn new() -> Self {
BinaryTree::Empty
}
fn insert(&mut self, value: T) {
match self {
BinaryTree::Empty => {
*self = BinaryTree::Leaf(value);
}
BinaryTree::Leaf(ref current_value) => {
let mut new_node = BinaryTree::Node(
current_value,
Box::new(BinaryTree::Empty),
Box::new(BinaryTree::Empty),
);
new_node.insert(value);
*self = new_node;
}
BinaryTree::Node(ref current_value, ref mut left, ref mut right) => {
if value < *current_value {
left.insert(value);
} else {
right.insert(value);
}
}
}
}
fn contains(&self, value: &T) -> bool {
match self {
BinaryTree::Empty => false,
BinaryTree::Leaf(ref current_value) => current_value == value,
BinaryTree::Node(ref current_value, left, right) => {
if value == current_value {
true
} else if value < current_value {
left.contains(value)
} else {
right.contains(value)
}
}
}
}
}
let mut tree = BinaryTree::new();
tree.insert(5);
tree.insert(3);
tree.insert(7);
tree.insert(1);
tree.insert(9);
println!("Binary tree: {:?}", tree);
println!("Contains 3: {}", tree.contains(&3));
println!("Contains 8: {}", tree.contains(&8));
}
Box的性能特性
rust
fn box_performance() {
use std::time::Instant;
// 测试Box与栈数据的性能差异
const SIZE: usize = 1_000_000;
// 在栈上创建大数组(可能导致栈溢出)
// let stack_array = [0u8; SIZE]; // 这可能在编译时或运行时失败
// 使用Box在堆上分配
let start = Instant::now();
let heap_array = Box::new([0u8; SIZE]);
let box_time = start.elapsed();
println!("Box allocation time: {:?}", box_time);
println!("Heap array length: {}", heap_array.len());
// 测试访问性能
let start = Instant::now();
let mut sum = 0;
for &byte in heap_array.iter() {
sum += byte as u64;
}
let access_time = start.elapsed();
println!("Access time: {:?}, Sum: {}", access_time, sum);
// Box与向量的比较
let start = Instant::now();
let vec_data = vec![0u8; SIZE];
let vec_time = start.elapsed();
let start = Instant::now();
let box_data = Box::new([0u8; SIZE]);
let box_array_time = start.elapsed();
println!("Vec allocation time: {:?}", vec_time);
println!("Box<[u8]> allocation time: {:?}", box_array_time);
// 内存布局分析
println!("Size of Box<[u8; 1000]>: {}", std::mem::size_of::<Box<[u8; 1000]>>());
println!("Size of Vec<u8>: {}", std::mem::size_of::<Vec<u8>>());
println!("Size of &[u8]: {}", std::mem::size_of::<&[u8]>());
}
14.2 Deref和Drop trait
Deref Trait:智能指针的核心
Deref trait允许我们重载解引用运算符*,这是智能指针能够像普通引用一样工作的关键。
基本Deref实现
rust
use std::ops::Deref;
// 自定义智能指针
struct MyBox<T>(T);
impl<T> MyBox<T> {
fn new(x: T) -> Self {
MyBox(x)
}
}
impl<T> Deref for MyBox<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
&self.0
}
}
// 为MyBox实现Drop trait
impl<T> Drop for MyBox<T> {
fn drop(&mut self) {
println!("Dropping MyBox with data");
}
}
fn deref_basics() {
let x = 5;
let y = MyBox::new(x);
// 由于实现了Deref,我们可以解引用MyBox
assert_eq!(5, *y);
assert_eq!(5, *(y.deref())); // 显式调用
// 自动解引用转换
fn takes_reference(s: &str) {
println!("String: {}", s);
}
let my_string = MyBox::new(String::from("Hello, Rust!"));
takes_reference(&my_string); // 自动调用deref: &MyBox<String> -> &String -> &str
// 多级解引用转换
let nested = MyBox::new(MyBox::new(42));
println!("Nested value: {}", **nested);
}
解引用转换(Deref Coercion)
解引用转换是Rust的一个便利特性,它自动将实现了Deref的类型的引用转换为Deref::Target的引用。
rust
fn deref_coercion_demo() {
// 字符串解引用转换
let boxed_string = Box::new(String::from("hello"));
// Box<String> 自动解引用为 &String
let string_ref: &String = &boxed_string;
// &String 自动解引用为 &str
let str_ref: &str = &boxed_string;
println!("Box<String> as &str: {}", str_ref);
// 在函数参数中的解引用转换
fn print_length(s: &str) {
println!("Length: {}", s.len());
}
let my_string = String::from("hello world");
let boxed_string = Box::new(my_string);
let rc_string = std::rc::Rc::new(String::from("shared string"));
// 所有这些类型都可以自动转换为&str
print_length(&boxed_string); // Box<String> -> &str
print_length(&rc_string); // Rc<String> -> &str
print_length("literal"); // &'static str -> &str
// 自定义类型的解引用转换
struct Wrapper {
value: String,
}
impl Deref for Wrapper {
type Target = String;
fn deref(&self) -> &Self::Target {
&self.value
}
}
let wrapper = Wrapper {
value: "wrapped string".to_string(),
};
print_length(&wrapper); // Wrapper -> &String -> &str
}
Drop Trait:资源清理
Drop trait允许我们在值离开作用域时执行自定义清理代码。
基本Drop实现
rust
struct CustomSmartPointer {
data: String,
}
impl Drop for CustomSmartPointer {
fn drop(&mut self) {
println!("Dropping CustomSmartPointer with data: `{}`", self.data);
}
}
fn drop_basics() {
let c = CustomSmartPointer {
data: String::from("my stuff"),
};
let d = CustomSmartPointer {
data: String::from("other stuff"),
};
println!("CustomSmartPointers created.");
// c和d离开作用域时,会自动调用drop方法
}
// 更实用的Drop示例:文件描述符管理
struct FileDescriptor {
fd: i32,
filename: String,
}
impl FileDescriptor {
fn new(filename: &str) -> Result<Self, String> {
// 模拟打开文件
println!("Opening file: {}", filename);
let fd = 42; // 模拟文件描述符
Ok(FileDescriptor {
fd,
filename: filename.to_string(),
})
}
fn read(&self) -> String {
format!("Data from file {} (fd: {})", self.filename, self.fd)
}
}
impl Drop for FileDescriptor {
fn drop(&mut self) {
println!("Closing file: {} (fd: {})", self.filename, self.fd);
// 在实际实现中,这里会调用close系统调用
}
}
fn resource_management() {
{
let file = FileDescriptor::new("example.txt").unwrap();
println!("File content: {}", file.read());
// file在这里离开作用域,自动调用drop关闭文件
}
println!("File has been closed automatically");
// 手动提前释放资源
let early_file = FileDescriptor::new("early_close.txt").unwrap();
println!("Early file content: {}", early_file.read());
drop(early_file); // 手动调用drop
println!("File was closed early");
// early_file不能再被使用
}
高级Drop模式
rust
fn advanced_drop_patterns() {
// 1. 条件性资源清理
struct ConditionalResource {
data: Vec<u8>,
should_cleanup: bool,
}
impl ConditionalResource {
fn new(data: Vec<u8>, should_cleanup: bool) -> Self {
ConditionalResource { data, should_cleanup }
}
}
impl Drop for ConditionalResource {
fn drop(&mut self) {
if self.should_cleanup {
println!("Cleaning up resource with {} bytes", self.data.len());
// 执行清理操作,比如清零敏感数据
for byte in &mut self.data {
*byte = 0;
}
} else {
println!("Skipping cleanup for resource");
}
}
}
let sensitive = ConditionalResource::new(vec![1, 2, 3, 4, 5], true);
let normal = ConditionalResource::new(vec![6, 7, 8], false);
// 2. 引用计数与Drop
struct SharedResource {
name: String,
ref_count: std::rc::Rc<()>,
}
impl SharedResource {
fn new(name: &str) -> Self {
SharedResource {
name: name.to_string(),
ref_count: std::rc::Rc::new(()),
}
}
fn clone(&self) -> Self {
SharedResource {
name: self.name.clone(),
ref_count: self.ref_count.clone(),
}
}
}
impl Drop for SharedResource {
fn drop(&mut self) {
// 当Rc的强引用计数为1时,说明这是最后一个所有者
if std::rc::Rc::strong_count(&self.ref_count) == 1 {
println!("Releasing exclusive access to: {}", self.name);
} else {
println!("Dropping shared access to: {} ({} references remain)",
self.name, std::rc::Rc::strong_count(&self.ref_count) - 1);
}
}
}
let resource1 = SharedResource::new("database_connection");
let resource2 = resource1.clone();
let resource3 = resource2.clone();
println!("Created multiple shared resources");
// 当每个资源离开作用域时,Drop会告诉我们引用计数情况
}
Deref和Drop的交互
rust
fn deref_and_drop_interaction() {
// 同时实现Deref和Drop的智能指针
struct SmartVector<T> {
data: Vec<T>,
name: String,
}
impl<T> SmartVector<T> {
fn new(name: &str) -> Self {
SmartVector {
data: Vec::new(),
name: name.to_string(),
}
}
fn push(&mut self, item: T) {
self.data.push(item);
}
}
impl<T> Deref for SmartVector<T> {
type Target = Vec<T>;
fn deref(&self) -> &Self::Target {
&self.data
}
}
impl<T> DerefMut for SmartVector<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.data
}
}
impl<T> Drop for SmartVector<T> {
fn drop(&mut self) {
println!("Dropping SmartVector '{}' with {} elements",
self.name, self.data.len());
}
}
{
let mut smart_vec = SmartVector::new("my_vector");
smart_vec.push(1);
smart_vec.push(2);
smart_vec.push(3);
// 由于实现了Deref,我们可以使用Vec的所有方法
println!("Length: {}", smart_vec.len());
println!("First: {}", smart_vec[0]);
// 由于实现了DerefMut,我们可以修改内容
smart_vec[0] = 100;
println!("After modification: {:?}", *smart_vec);
// 离开作用域时自动调用Drop
}
// 使用Box<dyn Drop>存储不同类型的可清理对象
let cleanup_objects: Vec<Box<dyn Drop>> = vec![
Box::new(CustomSmartPointer { data: "first".to_string() }),
Box::new(CustomSmartPointer { data: "second".to_string() }),
];
println!("Cleanup objects vector created");
// 当vector离开作用域时,所有元素都会调用各自的drop方法
}
14.3 Rc引用计数指针
引用计数基础
Rc<T>(引用计数智能指针)允许多个所有者同时拥有相同的数据。它通过引用计数来跟踪数据的引用数量,当计数变为0时自动清理数据。
基本Rc使用
rust
use std::rc::Rc;
fn rc_basics() {
// 创建引用计数指针
let rc_data = Rc::new(String::from("Hello, Rc!"));
println!("Data: {}, strong count: {}", rc_data, Rc::strong_count(&rc_data));
// 克隆会增加引用计数
let rc_clone1 = Rc::clone(&rc_data);
println!("After first clone, strong count: {}", Rc::strong_count(&rc_data));
{
let rc_clone2 = Rc::clone(&rc_data);
println!("Inside scope, strong count: {}", Rc::strong_count(&rc_data));
// rc_clone2 离开作用域时,计数减1
}
println!("After inner scope, strong count: {}", Rc::strong_count(&rc_data));
// 所有引用都离开作用域后数据被清理
println!("All Rc clones will be dropped now");
}
// 共享数据场景
fn shared_data_scenarios() {
#[derive(Debug)]
struct Config {
database_url: String,
max_connections: u32,
timeout: u64,
}
let config = Rc::new(Config {
database_url: "postgres://localhost/mydb".to_string(),
max_connections: 100,
timeout: 30,
});
// 多个组件共享相同的配置
struct DatabaseConnection {
config: Rc<Config>,
connection_id: u32,
}
impl DatabaseConnection {
fn new(config: Rc<Config>, connection_id: u32) -> Self {
println!("Creating connection {} with config: {:?}", connection_id, config);
DatabaseConnection { config, connection_id }
}
}
let mut connections = Vec::new();
for i in 0..3 {
let connection = DatabaseConnection::new(Rc::clone(&config), i);
connections.push(connection);
}
println!("Created {} connections", connections.len());
println!("Config reference count: {}", Rc::strong_count(&config));
// 所有连接共享同一个配置对象,没有重复的内存分配
}
图数据结构与Rc
引用计数特别适合构建图状数据结构,其中节点可能被多个其他节点引用。
rust
fn graph_data_structures() {
use std::rc::Rc;
// 简单的图节点
#[derive(Debug)]
struct GraphNode {
value: i32,
neighbors: Vec<Rc<GraphNode>>,
}
impl GraphNode {
fn new(value: i32) -> Rc<Self> {
Rc::new(GraphNode {
value,
neighbors: Vec::new(),
})
}
fn add_neighbor(node: &Rc<GraphNode>, neighbor: &Rc<GraphNode>) {
// 我们需要可变引用,但Rc默认不可变
// 这里使用RefCell或其它内部可变性(在下一节讨论)
// 目前我们无法修改,这里只是演示结构
}
}
// 创建一些节点
let node1 = GraphNode::new(1);
let node2 = GraphNode::new(2);
let node3 = GraphNode::new(3);
println!("Node1 count: {}", Rc::strong_count(&node1));
println!("Node2 count: {}", Rc::strong_count(&node2));
println!("Node3 count: {}", Rc::strong_count(&node3));
// 树状结构更适合Rc
#[derive(Debug)]
struct TreeNode {
value: i32,
children: Vec<Rc<TreeNode>>,
}
impl TreeNode {
fn new(value: i32) -> Rc<Self> {
Rc::new(TreeNode {
value,
children: Vec::new(),
})
}
fn add_child(parent: &Rc<TreeNode>, child: Rc<TreeNode>) {
// 这里我们需要内部可变性,稍后讨论
}
}
// 构建树结构
let root = TreeNode::new(0);
let child1 = TreeNode::new(1);
let child2 = TreeNode::new(2);
let grandchild = TreeNode::new(3);
println!("Tree nodes created");
println!("Root count: {}", Rc::strong_count(&root));
}
Rc的局限性
rust
fn rc_limitations() {
// Rc<T> 不允许可变引用,因为可能有多个所有者
let shared_data = Rc::new(42);
// 这行会编译错误:不能可变借用Rc内部的数据
// *shared_data = 100;
println!("Shared data: {}", shared_data);
// Rc不是线程安全的
let non_send_data = Rc::new("not thread safe");
// 尝试在线程间共享会导致编译错误
// std::thread::spawn(move || {
// println!("In thread: {}", non_send_data);
// });
println!("Rc cannot be sent between threads safely");
// 循环引用问题
#[derive(Debug)]
struct Node {
value: i32,
next: Option<Rc<Node>>,
}
let node1 = Rc::new(Node {
value: 1,
next: None,
});
let node2 = Rc::new(Node {
value: 2,
next: Some(Rc::clone(&node1)),
});
// 创建循环引用(这里实际上没有,因为node1没有指向node2)
// 但如果node1也指向node2,就会形成循环引用,导致内存泄漏
println!("Node1: {:?}", node1);
println!("Node2: {:?}", node2);
}
14.4 RefCell与内部可变性
内部可变性模式
内部可变性是Rust的设计模式之一,它允许在拥有不可变引用时修改数据。这通过运行时借用检查来实现,而不是编译时。
RefCell基础
rust
use std::cell::RefCell;
fn refcell_basics() {
// 创建RefCell
let ref_cell = RefCell::new(String::from("hello"));
println!("Initial value: {}", ref_cell.borrow());
// 获取可变借用
{
let mut borrowed_mut = ref_cell.borrow_mut();
borrowed_mut.push_str(", world!");
println!("After mutation: {}", borrowed_mut);
} // 借用在这里结束
// 现在可以再次借用
println!("Final value: {}", ref_cell.borrow());
// 运行时借用检查
let cell = RefCell::new(42);
let borrow1 = cell.borrow(); // 不可变借用OK
println!("First borrow: {}", borrow1);
// 尝试在不可变借用存在时获取可变借用
// let mut borrow2 = cell.borrow_mut(); // 这会panic!
// 必须先释放不可变借用
drop(borrow1);
let mut borrow2 = cell.borrow_mut(); // 现在OK
*borrow2 = 100;
println!("After mutable borrow: {}", borrow2);
}
结合Rc和RefCell
Rc<RefCell<T>>是一种常见的模式,它允许多个所有者并且能够修改数据。
rust
fn rc_and_refcell_combination() {
use std::rc::Rc;
use std::cell::RefCell;
// 可变的共享数据
#[derive(Debug)]
struct SharedData {
value: i32,
history: Vec<i32>,
}
impl SharedData {
fn new(value: i32) -> Self {
SharedData {
value,
history: vec![value],
}
}
fn update(&mut self, new_value: i32) {
self.value = new_value;
self.history.push(new_value);
}
fn get_history(&self) -> &[i32] {
&self.history
}
}
// 创建可变的共享数据
let shared_data = Rc::new(RefCell::new(SharedData::new(0)));
// 多个所有者都可以修改数据
let owner1 = Rc::clone(&shared_data);
let owner2 = Rc::clone(&shared_data);
// 通过第一个所有者修改数据
{
let mut borrowed = owner1.borrow_mut();
borrowed.update(42);
println!("After owner1 update: {:?}", borrowed);
}
// 通过第二个所有者修改数据
{
let mut borrowed = owner2.borrow_mut();
borrowed.update(100);
println!("After owner2 update: {:?}", borrowed);
}
// 读取最终状态
let final_state = shared_data.borrow();
println!("Final state: {:?}", *final_state);
println!("History: {:?}", final_state.get_history());
// 在实际应用中的例子:可观察的数据模型
struct Observable<T> {
value: Rc<RefCell<T>>,
observers: Rc<RefCell<Vec<Box<dyn Fn(&T)>>>>,
}
impl<T> Observable<T> {
fn new(initial_value: T) -> Self {
Observable {
value: Rc::new(RefCell::new(initial_value)),
observers: Rc::new(RefCell::new(Vec::new())),
}
}
fn set_value(&self, new_value: T) {
*self.value.borrow_mut() = new_value;
self.notify_observers();
}
fn get_value(&self) -> Rc<RefCell<T>> {
Rc::clone(&self.value)
}
fn add_observer<F>(&self, observer: F)
where
F: Fn(&T) + 'static,
{
self.observers.borrow_mut().push(Box::new(observer));
}
fn notify_observers(&self) {
let value = self.value.borrow();
for observer in self.observers.borrow().iter() {
observer(&value);
}
}
}
let observable = Observable::new(0);
// 添加观察者
observable.add_observer(|value| {
println!("Observer 1: Value changed to {}", value);
});
observable.add_observer(|value| {
println!("Observer 2: New value is {}", value);
});
// 修改值会通知所有观察者
observable.set_value(10);
observable.set_value(20);
}
实战:实现一个简单的DOM树
让我们用Rc和RefCell构建一个简化的DOM树来展示内部可变性的实际应用:
rust
fn dom_tree_example() {
use std::rc::Rc;
use std::cell::RefCell;
// DOM节点类型
#[derive(Debug)]
struct DomNode {
tag_name: String,
attributes: RefCell<Vec<(String, String)>>,
children: RefCell<Vec<Rc<DomNode>>>,
parent: RefCell<Option<Rc<DomNode>>>,
}
impl DomNode {
fn new(tag_name: &str) -> Rc<Self> {
Rc::new(DomNode {
tag_name: tag_name.to_string(),
attributes: RefCell::new(Vec::new()),
children: RefCell::new(Vec::new()),
parent: RefCell::new(None),
})
}
fn set_attribute(&self, name: &str, value: &str) {
let mut attributes = self.attributes.borrow_mut();
// 移除已存在的同名属性
attributes.retain(|(attr_name, _)| attr_name != name);
attributes.push((name.to_string(), value.to_string()));
}
fn append_child(parent: &Rc<Self>, child: &Rc<Self>) {
// 添加到父节点的子节点列表
parent.children.borrow_mut().push(Rc::clone(child));
// 设置子节点的父节点
*child.parent.borrow_mut() = Some(Rc::clone(parent));
}
fn remove_child(parent: &Rc<Self>, child: &Rc<Self>) -> bool {
let mut children = parent.children.borrow_mut();
if let Some(pos) = children.iter().position(|c| Rc::ptr_eq(c, child)) {
children.remove(pos);
*child.parent.borrow_mut() = None;
true
} else {
false
}
}
fn find_by_tag_name(&self, tag_name: &str) -> Vec<Rc<DomNode>> {
let mut results = Vec::new();
if self.tag_name == tag_name {
results.push(Rc::clone(&Rc::new(self))); // 这里需要修复
}
for child in self.children.borrow().iter() {
results.extend(child.find_by_tag_name(tag_name));
}
results
}
fn to_html(&self, indent: usize) -> String {
let indent_str = " ".repeat(indent);
let mut html = format!("{}<{}", indent_str, self.tag_name);
// 添加属性
for (name, value) in self.attributes.borrow().iter() {
html.push_str(&format!(" {}=\"{}\"", name, value));
}
let children = self.children.borrow();
if children.is_empty() {
html.push_str(" />\n");
} else {
html.push_str(">\n");
// 添加子节点
for child in children.iter() {
html.push_str(&child.to_html(indent + 1));
}
html.push_str(&format!("{}</{}>\n", indent_str, self.tag_name));
}
html
}
}
// 构建DOM树
let html = DomNode::new("html");
let head = DomNode::new("head");
let title = DomNode::new("title");
title.set_attribute("text", "My Page");
let body = DomNode::new("body");
body.set_attribute("class", "main-content");
let h1 = DomNode::new("h1");
h1.set_attribute("id", "main-heading");
let p1 = DomNode::new("p");
let p2 = DomNode::new("p");
// 构建树结构
DomNode::append_child(&html, &head);
DomNode::append_child(&html, &body);
DomNode::append_child(&head, &title);
DomNode::append_child(&body, &h1);
DomNode::append_child(&body, &p1);
DomNode::append_child(&body, &p2);
// 输出HTML
println!("Generated HTML:");
println!("{}", html.to_html(0));
// 查找元素
let paragraphs = body.find_by_tag_name("p");
println!("Found {} paragraphs", paragraphs.len());
// 修改结构
DomNode::remove_child(&body, &p1);
println!("\nAfter removing one paragraph:");
println!("{}", html.to_html(0));
}
选择指南:何时使用哪种智能指针
rust
fn smart_pointer_selection_guide() {
println!("=== 智能指针选择指南 ===\n");
println!("使用 Box<T> 当:");
println!("1. 需要在堆上分配数据时");
println!("2. 有递归数据结构时");
println!("3. 想转移大数据的所有权而不拷贝时");
println!("4. 拥有 trait 对象但不知道具体类型时\n");
println!("使用 Rc<T> 当:");
println!("1. 需要多个所有者共享相同数据时");
println!("2. 构建图状或树状数据结构时");
println!("3. 数据是只读的,但需要多处访问时\n");
println!("使用 RefCell<T> 当:");
println!("1. 需要内部可变性时");
println!("2. 有逻辑上不可变但需要部分修改的数据时");
println!("3. 结合 Rc<T> 创建可变的共享数据时\n");
println!("组合模式:");
println!("Rc<RefCell<T>> - 可变的共享数据");
println!("Rc<Vec<RefCell<T>>> - 共享的可变集合");
println!("Box<dyn Trait> - trait 对象\n");
// 性能考虑
println!("性能考虑:");
println!("- Box<T> 几乎没有运行时开销");
println!("- Rc<T> 有引用计数开销");
println!("- RefCell<T> 有运行时借用检查开销");
println!("- 在性能关键代码中要谨慎使用 Rc 和 RefCell");
// 线程安全考虑
println!("\n线程安全:");
println!("- Box<T> 是线程安全的(如果 T 是 Send)");
println!("- Rc<T> 不是线程安全的");
println!("- RefCell<T> 不是线程安全的");
println!("- 对于多线程,使用 Arc<T> 和 Mutex<T>");
}
fn main() {
box_basics();
box_use_cases();
recursive_data_structures();
box_performance();
deref_basics();
deref_coercion_demo();
drop_basics();
resource_management();
advanced_drop_patterns();
deref_and_drop_interaction();
rc_basics();
shared_data_scenarios();
graph_data_structures();
rc_limitations();
refcell_basics();
rc_and_refcell_combination();
dom_tree_example();
smart_pointer_selection_guide();
}
总结
智能指针是Rust内存管理系统的核心组成部分,它们提供了在保证内存安全的同时实现复杂所有权模式的能力。通过本章的学习,我们掌握了:
- Box:用于堆分配、递归数据结构和trait对象
- Deref和Drop trait:智能指针的行为基础,实现解引用和资源清理
- Rc:引用计数智能指针,允许多个所有者共享数据
- RefCell:内部可变性模式,允许在运行时进行借用检查
这些智能指针可以组合使用,形成强大的模式来处理各种复杂场景。理解每种智能指针的适用场景和性能特征对于编写高效、安全的Rust代码至关重要。
在下一章中,我们将探讨Rust的并发编程特性,学习如何使用线程、消息传递和共享状态来构建并发应用程序。