当前位置: 首页 > news >正文

第14章 智能指针

在这里插入图片描述

文章目录

  • 第14章 智能指针
    • 14.1 Box<T>堆内存分配
      • Box基础与堆内存管理
        • 基本使用
        • 使用Box的场景
      • 递归数据结构与Box
      • Box的性能特性
    • 14.2 Deref和Drop trait
      • Deref Trait:智能指针的核心
        • 基本Deref实现
        • 解引用转换(Deref Coercion)
      • Drop Trait:资源清理
        • 基本Drop实现
        • 高级Drop模式
      • Deref和Drop的交互
    • 14.3 Rc<T>引用计数指针
      • 引用计数基础
        • 基本Rc使用
      • 图数据结构与Rc
      • Rc的局限性
    • 14.4 RefCell<T>与内部可变性
      • 内部可变性模式
        • RefCell基础
      • 结合Rc和RefCell
      • 实战:实现一个简单的DOM树
      • 选择指南:何时使用哪种智能指针
    • 总结

第14章 智能指针

智能指针是Rust中管理堆内存和实现复杂所有权模式的核心工具。它们不仅像普通指针一样指向某个内存地址,还拥有额外的元数据和功能,如引用计数、内部可变性等。Rust的智能指针系统建立在所有权和借用规则之上,提供了在编译时和运行时保证内存安全的多种方式。本章将深入探讨各种智能指针的特性和使用场景,从基础的Box<T>到复杂的引用计数和内部可变性模式。

14.1 Box堆内存分配

Box基础与堆内存管理

Box<T>是Rust中最简单的智能指针,它允许将数据存储在堆上而不是栈上。Box在栈中存储一个指向堆数据的指针,当Box离开作用域时,会自动释放其指向的堆内存。

基本使用
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);// 解引用Boxlet 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的场景
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需要在编译时知道类型的大小。

// 使用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 -> Nillet 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的性能特性

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实现
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,我们可以解引用MyBoxassert_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的引用。

fn deref_coercion_demo() {// 字符串解引用转换let boxed_string = Box::new(String::from("hello"));// Box<String> 自动解引用为 &Stringlet string_ref: &String = &boxed_string;// &String 自动解引用为 &strlet 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"));// 所有这些类型都可以自动转换为&strprint_length(&boxed_string);    // Box<String> -> &strprint_length(&rc_string);       // Rc<String> -> &strprint_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实现
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); // 手动调用dropprintln!("File was closed early");// early_file不能再被使用
}
高级Drop模式
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. 引用计数与Dropstruct 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的交互

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使用
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

引用计数特别适合构建图状数据结构,其中节点可能被多个其他节点引用。

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的局限性

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基础
use std::cell::RefCell;fn refcell_basics() {// 创建RefCelllet 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(); // 不可变借用OKprintln!("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>>是一种常见的模式,它允许多个所有者并且能够修改数据。

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树

让我们用RcRefCell构建一个简化的DOM树来展示内部可变性的实际应用:

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);// 输出HTMLprintln!("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));
}

选择指南:何时使用哪种智能指针

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内存管理系统的核心组成部分,它们提供了在保证内存安全的同时实现复杂所有权模式的能力。通过本章的学习,我们掌握了:

  1. Box:用于堆分配、递归数据结构和trait对象
  2. Deref和Drop trait:智能指针的行为基础,实现解引用和资源清理
  3. Rc:引用计数智能指针,允许多个所有者共享数据
  4. RefCell:内部可变性模式,允许在运行时进行借用检查

这些智能指针可以组合使用,形成强大的模式来处理各种复杂场景。理解每种智能指针的适用场景和性能特征对于编写高效、安全的Rust代码至关重要。

在下一章中,我们将探讨Rust的并发编程特性,学习如何使用线程、消息传递和共享状态来构建并发应用程序。

http://www.dtcms.com/a/601928.html

相关文章:

  • GSV6128E/ACP---嵌入式Display port 1.4到 LVDS转换器,带音频提取和嵌入式MCU
  • 网站建设ftp上传是空目录仿做网站的网站
  • c 网站开发代码辅助色网站
  • 无法下载依赖:pentaho-aggdesigner-algorithm/5.1.5-jhyde
  • sward实战教程系列(1) - 安装与配置
  • C语言编译环境 | 配置和优化你的开发环境,让编程更加高效
  • 《Vue项目开发实战》第五章:组件封装--Form
  • 数据管理战略|流程与IT变革、量化闭环
  • 外卖网站制作wordpress主题 制作教程
  • 企业网站总承包建设模式关键步骤wordpress安装主题后打不开
  • 在纷扰世界里找到自己的安心之道——《安心之道》的实践指南
  • 网站建设的公司太多了东莞南城房价
  • 【python】使用opencv的模板匹配进行自动化点击
  • leetcode 2654 使数组所有元素变成1的最少操作次数
  • 数据结构(长期更新)第8讲:队列
  • LKT4305安全芯片身份认证介绍
  • 看门狗超时时间的理解
  • C语言编译器手机教程 | 轻松在手机上编写和编译C语言程序
  • 基于SpringBoot的企业资产管理系统开发与设计
  • 黄骅做网站价格莱芜金点子招工小时工
  • 速卖通网站怎样做店面的二维码厦门网站建设
  • 好创意网站有哪些方面幸运28网站开发
  • AI小白入门:什么是RAG技术?
  • 【一天一个计算机知识】—— 【编程百度】条件编译
  • 网站分享注册公司代理电话
  • 免费制作一个企业网站广告设计公司网页
  • Gradle vs Maven 详细对比
  • [Column#187] 10data_struct | IP速查表 | 协议TCPUDP | DeepSeek-OCR
  • 生产级HMACSHA256签名与验签案例
  • 腾讯云服务器搭建网站漯河网站建设费用