27·智能指针进阶

智能指针 Box/Rc/Arc

智能指针 Box/Rc/Arc

学习目标

  1. 理解 Box<T> 堆分配
  2. 理解 Rc<T> 引用计数
  3. 理解 Arc<T> 原子引用计数
  4. 掌握使用场景

核心概念

Box<T>

fn main() {
    // 堆分配
    let b = Box::new(5);
    println!("b = {}", b);

    // 递归类型(编译器需要知道大小)
    enum List<T> {
        Cons(T, Box<List<T>>),
        Nil,
    }

    use List::{Cons, Nil};
    let list = Cons(1, Box::new(Cons(2, Box::new(Cons(3, Box::new(Nil))))));

    // 大数据移动到堆上
    let large_array = Box::new([0u8; 1_000_000]);
}

Rc<T>(单线程引用计数)

use std::rc::Rc;

fn main() {
    let a = Rc::new(5);
    let b = Rc::clone(&a);  // 引用计数 +1
    let c = Rc::clone(&a);  // 引用计数 +1

    println!("引用计数: {}", Rc::strong_count(&a));  // 3
    println!("值: {}", *a);

    // 共享所有权
    let shared = Rc::new(String::from("hello"));
    let s1 = Rc::clone(&shared);
    let s2 = Rc::clone(&shared);
    println!("{} {} {}", shared, s1, s2);
}

Arc<T>(线程安全引用计数)

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

fn main() {
    let data = Arc::new(vec![1, 2, 3, 4, 5]);
    let mut handles = vec![];

    for i in 0..3 {
        let data = Arc::clone(&data);
        let handle = thread::spawn(move || {
            println!("线程 {}: {:?}", i, data);
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }
}

Rc vs Arc

类型线程安全性能使用场景
Rc<T>单线程共享
Arc<T>略慢多线程共享

共享图结构

use std::rc::Rc;

#[derive(Debug)]
struct Node {
    value: i32,
    neighbors: Vec<Rc<Node>>,
}

fn main() {
    let node1 = Rc::new(Node { value: 1, neighbors: vec![] });
    let node2 = Rc::new(Node { value: 2, neighbors: vec![Rc::clone(&node1)] });
    let node3 = Rc::new(Node { value: 3, neighbors: vec![Rc::clone(&node1)] });

    // node1 被 node2 和 node3 共享
    println!("node1 引用计数: {}", Rc::strong_count(&node1));  // 3
}

实践练习

练习 1:共享配置

use std::rc::Rc;

struct Config {
    database_url: String,
    max_connections: u32,
}

struct Service {
    name: String,
    config: Rc<Config>,
}

impl Service {
    fn new(name: &str, config: Rc<Config>) -> Self {
        Service { name: String::from(name), config }
    }

    fn info(&self) {
        println!("{}: {} (max: {})", self.name, self.config.database_url, self.config.max_connections);
    }
}

fn main() {
    let config = Rc::new(Config {
        database_url: String::from("postgres://localhost/mydb"),
        max_connections: 10,
    });

    let svc1 = Service::new("API", Rc::clone(&config));
    let svc2 = Service::new("Worker", Rc::clone(&config));

    svc1.info();
    svc2.info();
}

常见错误

1. 循环引用

use std::rc::Rc;
use std::cell::RefCell;

// ❌ 循环引用导致内存泄漏
// A → B → A(强引用计数永远不为 0)

// ✅ 用 Weak<T> 打破循环

2. Rc 用于多线程

// ❌ Rc 不是线程安全的
// let data = Rc::new(5);
// thread::spawn(move || { println!("{}", data); });

// ✅ 用 Arc
let data = Arc::new(5);

小结

类型场景
Box<T>堆分配,单一所有者
Rc<T>单线程多所有者
Arc<T>多线程多所有者
Weak<T>弱引用,避免循环

练习编辑器

rust
Loading...