Skip to content

Rust 智能指针

智能指针是 Rust 中具有额外功能的指针类型,它们不仅存储内存地址,还包含额外的元数据和功能。本章节将介绍 Rust 中的智能指针。

智能指针与引用的区别

  • 引用:只是借用值,没有所有权
  • 智能指针:拥有它们指向的数据

Box<T>

Box<T> 是最基本的智能指针,用于在堆上分配内存:

rust
fn main() {
    // 在堆上分配一个 i32
    let b = Box::new(5);
    println!("b = {}", b);
}

用途

  • 当类型大小不确定时
  • 当需要在编译时转移所有权时
  • 当需要一个值的大小在编译时确定时

Rc<T>

Rc<T> 是引用计数智能指针,用于多个所有者共享数据:

rust
use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a);
    let c = Rc::clone(&a);
    
    println!("Reference count: {}", Rc::strong_count(&a));
    println!("a = {}, b = {}, c = {}", a, b, c);
}

用途

  • 当需要多个所有者共享数据时
  • 当数据的生命周期在编译时无法确定时

RefCell<T>

RefCell<T> 提供了内部可变性,允许在不可变引用的情况下修改数据:

rust
use std::cell::RefCell;

fn main() {
    let value = RefCell::new(5);
    
    // 获取可变引用并修改值
    *value.borrow_mut() += 1;
    
    // 获取不可变引用并读取值
    println!("Value: {}", *value.borrow());
}

用途

  • 当需要在不可变引用的情况下修改数据时
  • 当需要内部可变性时

Arc<T>

Arc<T> 是原子引用计数智能指针,用于多线程环境下的共享数据:

rust
use std::sync::Arc;
use std::thread;

fn main() {
    let shared_data = Arc::new(5);
    
    let mut handles = vec![];
    
    for _ in 0..10 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            println!("Data: {}", data);
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
}

用途

  • 当需要在多线程环境下共享数据时

Mutex<T>

Mutex<T> 提供了互斥访问,确保在同一时间只有一个线程可以访问数据:

rust
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let shared_data = Arc::new(Mutex::new(0));
    
    let mut handles = vec![];
    
    for _ in 0..10 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            let mut value = data.lock().unwrap();
            *value += 1;
        });
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("Final value: {}", *shared_data.lock().unwrap());
}

用途

  • 当需要在多线程环境下安全地修改共享数据时

RwLock<T>

RwLock&lt;T&gt; 提供了读写锁,允许多个读操作同时进行,但写操作需要独占访问:

rust
use std::sync::{Arc, RwLock};
use std::thread;

fn main() {
    let shared_data = Arc::new(RwLock::new(0));
    
    // 读线程
    let mut read_handles = vec![];
    for _ in 0..5 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            let value = data.read().unwrap();
            println!("Read value: {}", *value);
        });
        read_handles.push(handle);
    }
    
    // 写线程
    let mut write_handles = vec![];
    for i in 0..3 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            let mut value = data.write().unwrap();
            *value = i;
            println!("Write value: {}", *value);
        });
        write_handles.push(handle);
    }
    
    for handle in read_handles {
        handle.join().unwrap();
    }
    
    for handle in write_handles {
        handle.join().unwrap();
    }
}

用途

  • 当读操作远多于写操作时

总结

  • Box<T>:在堆上分配内存
  • Rc<T>:引用计数,用于多个所有者共享数据
  • RefCell<T>:内部可变性,允许在不可变引用的情况下修改数据
  • Arc<T>:原子引用计数,用于多线程环境
  • Mutex<T>:互斥锁,确保同一时间只有一个线程访问数据
  • RwLock<T>:读写锁,允许多个读操作同时进行

智能指针是 Rust 中管理内存和并发的重要工具。通过本章节的学习,你应该已经掌握了 Rust 中常用的智能指针类型及其用途。