第14章 智能指针

文章目录

第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树

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

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

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

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

相关推荐
zhong liu bin2 小时前
Java并发编程【JUC】【一】
java·开发语言·juc
陈老师还在写代码2 小时前
android studio 里的 activity 和 layout 是怎么关联上的
android·ide·android studio
老华带你飞2 小时前
医疗保健|医疗养老|基于Java+vue的医疗保健系统(源码+数据库+文档)
java·数据库·vue.js·spring boot·论文·毕设·医疗保健
摇滚侠2 小时前
GIT版本管理工具轻松入门 | TortoiseGit,解决冲突,笔记07
笔记·git
fire-flyer2 小时前
设计模式之观察者模式
java·开发语言
河铃旅鹿2 小时前
Android开发-java版:BroadcastReceiver广播
android·笔记·学习
咬_咬2 小时前
C++仿muduo库高并发服务器项目:Poller模块
服务器·开发语言·c++·epoll·muduo
程序员老刘2 小时前
华为小米都在布局的多屏协同,其实Android早就有了!只是你不知道...
android·flutter