rust语言学习笔记Trait(十一)Deref、DerefMut(解引用)

Deref 和 DerefMut 是用于实现‌智能指针 ‌行为的核心 Trait。它们允许自定义类型像普通引用一样工作,支持解引用操作符 *。

1、什么是 Deref

std::ops::Deref Trait 允许你重载解引用操作符 *。

  • ‌普通引用 ‌:&T 指向内存中的值,使用 * 可以获取该值。
  • ‌智能指针 ‌:如 Box<T>, Rc<T>, Arc<T>,它们是结构体,但实现了 Deref,因此可以像 &T 一样被解引用。

(1)Deref 的定义

rust 复制代码
pub trait Deref {
    // 关联类型:解引用后得到的目标类型
    type Target: ?Sized;

    // 核心方法:返回对内部数据的不可变引用
    fn deref(&self) -> &Self::Target;
}

(2)DerefMut (可变解引用)的定义

rust 复制代码
pub trait DerefMut: Deref {
    fn deref_mut(&mut self) -> &mut Self::Target;
}

2、自定义结构体实现 Deref 和 DerefMut

  • 实现 DerefMut,必须首先实现 Deref。
rust 复制代码
use std::ops::{Deref, DerefMut};

// 自定义结构体
#[derive(Debug)]
struct MyBox<T>(T);

// 实现 deref 不可变引用
impl<T> Deref for MyBox<T> {
    type Target = T;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

// 实现 deref_mut 可变引用,必须先实现 deref
impl<T> DerefMut for MyBox<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

fn main() {
    let mut ms = MyBox(8);
    
    *ms += 5;                       // 自动调用可变引用
    println!("{:?}", *ms);          // 自动调用不可变引用
    
    *(ms.deref_mut()) -= 3;          // 手动调用可变引用
    println!("{:?}", *(ms.deref())); // 手动调用不可变引用
}
  • *ms += 5,编译器查找 DerefMut 实现。

    可变引用转换过程:*ms -> *(ms.deref_mut()) -> *(&mut T) -> mut T
  • println!("{:?}", *ms);,编译器查找 Deref 实现。

    不可变引用转换过程:*ms -> *(ms.deref()) -> *(&T) -> T

3、最佳实践与陷阱

✅ 应该做的

  1. 仅为智能指针实现 Deref :
    Rust 官方建议 Deref 应仅用于智能指针类型(如 Box, Rc, Arc, RefCell 的守卫等)。目的是让智能指针"透明",让用户感觉像是在操作内部数据。
  2. ‌利用 Deref 提供切片视图 ‌:
    例如 Vec<T> 实现 Deref<Target = [T]>,String 实现 Deref<Target = str>。这使得你可以直接在这些集合上使用切片的方法。

❌ 不应该做的

  1. ‌不要为了便利而滥用 Deref :
    例如,不要为一个 User 结构体实现 Deref<Target = String> 以便直接调用字符串方法。这会隐藏数据的真实结构,导致代码难以阅读和维护。如果需要转换,请实现 AsRef<str> 或提供显式方法。
  2. Deref 不应失败 :
    deref() 方法签名返回的是引用 &Target,而不是 Result 或 Option。这意味着解引用操作必须总是成功。如果解引用可能失败(例如网络请求未完成),不应使用 Deref。
  3. 避免循环 Deref :
    确保 Target 类型不会间接地又解引用回原类型,否则会导致编译器无限递归或栈溢出。
相关推荐
FelixZhang0286 小时前
量化求真10|回测通过以后,策略就能上场吗?
人工智能·python·深度学习·学习·机器学习·金融·lstm
柯南46686 小时前
【AI开发之Rust】第 21 课:双端集成与出包 —— Android(.so→AAR)与 iOS(xcframework)
rust·编程语言
Vcaker6 小时前
Linux学习33-HPA动态扩缩容及k8s调度策略
linux·运维·学习
Amos_Web6 小时前
Rspack 源码解析(十六):多类型资源如何进入 Compilation.assets
前端·rust·前端框架
Norna6 小时前
时间轮里那行凭空出现的 +1
rust
金色光环6 小时前
概率论笔记:连续型随机变量函数的分布与尺度变换 连续型随机变量函数的分布:定义法与公式法推导
笔记·概率论
知识分享小能手6 小时前
C++ 学习教程,从入门到精通,C++内存模型和名称空间 — 详细知识点总结(9)
开发语言·c++·学习
AOI小白新手上路6 小时前
韦东山《ARM 架构与编程》3-2 GPIO 引脚操作方法概述 · 学习笔记
arm开发·学习·架构
维克兜率天7 小时前
【维克】均值回归:跌多了会涨,涨多了会跌
开发语言·笔记·python·算法·均值算法·回归·量化
zhangrelay7 小时前
ROS2 Lyrical实验5导航Nav2
linux·笔记·学习·ubuntu·机器人