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

DerefDerefMut 是用于实现‌智能指针 ‌行为的核心 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、自定义结构体实现 DerefDerefMut

  • 实现 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,而不是 ResultOption。这意味着解引用操作必须总是成功。如果解引用可能失败(例如网络请求未完成),不应使用 Deref
  3. 避免循环 Deref
    确保 Target 类型不会间接地又解引用回原类型,否则会导致编译器无限递归或栈溢出。
相关推荐
ouliten1 小时前
[Triton笔记6]层标准化
笔记
愚者Pro2 小时前
Flutter Widget组件学习(专为 Uniapp 转 Flutter 定制)
vue.js·学习·flutter·uni-app
玄米乌龙茶1233 小时前
思维导图笔记:Prompt工程
笔记·prompt
yzx9910133 小时前
从焦虑到掌控:关于学习AI工具的深度思考
人工智能·学习
Bechamz4 小时前
大数据开发学习Day42
大数据·学习
zhangrelay4 小时前
ROS 2 Lyrical Luth启程-Ubuntu26.04-
linux·笔记·学习·ubuntu
Undergoer_TW4 小时前
SLAM实战避坑笔记:基础矩阵退化场景分析与解决方案
笔记·线性代数·矩阵
Rust研习社4 小时前
从碎片化到标准化:cargo-bp 如何重构 Rust 开发逻辑
后端·rust·编程语言
锦鲤52144 小时前
机器学习学习笔记
笔记·学习·机器学习
minglie14 小时前
utf8转utf16
学习