Rust 智能指针

举报
福州司马懿 发表于 2025/12/19 14:15:22 2025/12/19
【摘要】 Rust 提供了多种智能指针(Smart Pointers),用于在堆上分配内存、管理资源(如文件、网络连接)或实现特殊行为(如引用计数)。以下是 Rust 中主要智能指针的用法和区别: 1. 核心智能指针 (1) Box<T>:堆分配用途:将数据存储在堆上,明确表示所有权转移。特点:适用于大型数据(避免栈溢出)。实现 Deref 和 Drop trait。支持递归类型(如链表、树)。 示例...

Rust 提供了多种智能指针(Smart Pointers),用于在堆上分配内存、管理资源(如文件、网络连接)或实现特殊行为(如引用计数)。以下是 Rust 中主要智能指针的用法和区别:


1. 核心智能指针

(1) Box<T>:堆分配

  • 用途:将数据存储在堆上,明确表示所有权转移。
  • 特点
    • 适用于大型数据(避免栈溢出)。
    • 实现 DerefDrop trait。
    • 支持递归类型(如链表、树)。

示例

fn main() {
    // 基本用法:堆分配
    let x = Box::new(5);
    println!("x = {}", x); // 自动解引用(Deref)

    // 递归类型(如链表)
    #[derive(Debug)]
    enum List {
        Cons(i32, Box<List>),
        Nil,
    }

    let list = List::Cons(1, Box::new(List::Cons(2, Box::new(List::Nil))));
    println!("{:?}", list);
}

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

  • 用途:在单线程中共享数据的多个所有权。
  • 特点
    • 通过 Rc::clone() 增加引用计数。
    • 当计数归零时自动释放内存。
    • 非线程安全(不实现 SendSync)。

示例

use std::rc::Rc;

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

    println!("a: {}, b: {}, c: {}", a, b, c);
    println!("引用计数: {}", Rc::strong_count(&a)); // 输出 3
}

(3) Arc<T>:多线程引用计数

  • 用途:在多线程中安全共享数据(线程安全版 Rc<T>)。
  • 特点
    • 使用原子操作管理引用计数(性能略低于 Rc)。
    • 通常与 Mutex/RwLock 配合实现可变共享数据。

示例

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

fn main() {
    let counter = Arc::new(0);
    let mut handles = vec![];

    for _ in 0..5 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            *counter.lock().unwrap() += 1; // 需要 Mutex 保护可变性
        });
        handles.push(handle);
    }

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

    println!("Result: {}", *counter.lock().unwrap());
}

(4) Cell<T>RefCell<T>:内部可变性

  • 用途:在不可变引用下修改数据(违反 Rust 常规借用规则)。
  • 区别
    • Cell<T>:适用于 Copy 类型(如 u32),通过 set/get 方法操作。
    • RefCell<T>:适用于任意类型,通过运行时借用检查(borrow/borrow_mut)。

示例

use std::cell::{Cell, RefCell};

fn main() {
    // Cell<T> 示例
    let x = Cell::new(10);
    x.set(20); // 不可变引用下修改值
    println!("x = {}", x.get());

    // RefCell<T> 示例
    let y = RefCell::new(vec![1, 2, 3]);
    {
        let mut v = y.borrow_mut(); // 获取可变借用
        v.push(4);
    } // 借用结束,自动释放
    println!("y = {:?}", y.borrow());
}

(5) Mutex<T>RwLock<T>:线程同步

  • 用途:保护共享数据的可变性。
  • 区别
    • Mutex<T>:独占访问(一次仅一个线程可访问)。
    • RwLock<T>:允许多个读或单个写(读多写少场景更高效)。

示例

use std::sync::{Mutex, RwLock};

fn main() {
    // Mutex 示例
    let m = Mutex::new(42);
    {
        let mut num = m.lock().unwrap();
        *num = 100;
    }

    // RwLock 示例
    let rw = RwLock::new(vec![]);
    {
        let mut v = rw.write().unwrap();
        v.push(1);
    }
    {
        let v = rw.read().unwrap();
        println!("v = {:?}", *v);
    }
}

2. 智能指针的选择指南

场景 推荐智能指针
单线程堆分配 Box<T>
单线程共享所有权 Rc<T>
多线程共享所有权 Arc<T>
内部可变性(单线程) Cell<T> / RefCell<T>
线程安全可变共享数据 Arc<Mutex<T>> / Arc<RwLock<T>>
避免循环引用 Arc<T> + Weak<T>

3. 高级用法

(1) 自定义智能指针

通过实现 DerefDrop trait 创建自定义智能指针:

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
    }
}

impl<T> Drop for MyBox<T> {
    fn drop(&mut self) {
        println!("Dropping MyBox!");
    }
}

fn main() {
    let x = MyBox::new(5);
    println!("x = {}", *x); // 自动调用 deref
}

(2) 避免循环引用

使用 Weak<T> 打破 Arc<T> 的循环引用:

use std::rc::{Arc, Weak};
use std::cell::RefCell;

#[derive(Debug)]
struct Node {
    value: i32,
    parent: RefCell<Weak<Node>>,
    children: RefCell<Vec<Arc<Node>>>,
}

fn main() {
    let leaf = Arc::new(Node {
        value: 3,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![]),
    });

    let root = Arc::new(Node {
        value: 1,
        parent: RefCell::new(Weak::new()),
        children: RefCell::new(vec![Arc::clone(&leaf)]),
    });

    *leaf.parent.borrow_mut() = Arc::downgrade(&root); // Weak 引用
}

总结

  • Box<T>:最简单的堆分配,适合明确所有权转移。
  • Rc<T> / Arc<T>:共享所有权,单线程用 Rc,多线程用 Arc
  • Cell<T> / RefCell<T>:内部可变性,绕过 Rust 借用规则。
  • Mutex<T> / RwLock<T>:线程安全可变共享数据。
  • Weak<T>:避免循环引用,常与 Arc 配合使用。

根据场景选择合适的智能指针,可以高效管理内存和资源,同时保持 Rust 的安全性。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。