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 类型不会间接地又解引用回原类型,否则会导致编译器无限递归或栈溢出。
相关推荐
MartinYeung52 小时前
[论文学习]自主性如何重塑个性化对LLM智能体隐私关切与信任的影响
人工智能·学习
FellAveal3 小时前
【Go语言入门学习笔记】Part18.工作池与WaitGroup(也即协程池)
笔记·学习·golang
xqqxqxxq4 小时前
Java Socket 多人聊天室(私聊+群聊)技术笔记(V4版本)
java·网络·笔记
菜鸟‍4 小时前
【论文学习】MICCAI 2024 || SGSeg:通过自引导机制实现胸部X光片语言引导分割的无文本推理
人工智能·深度学习·学习
龙仔7254 小时前
人大金仓OS_Core数据库自动备份实施笔记(银河麒麟Linux)
linux·数据库·笔记·备份·人大金仓
lazy H4 小时前
Git clone 怎么用?克隆项目及常见问题完整教程
大数据·git·后端·学习·搜索引擎·github
菜鸟‍4 小时前
【论文学习】arxiv 2024 || RoSIS:基于鲁棒框架重新审视文本提示式手术器械分割
人工智能·学习·计算机视觉
笨鸟先飞的橘猫5 小时前
只会脚本语言的游戏后端自我提升之路——c++学习(开篇)
学习·游戏
Z5998178416 小时前
c#软件开发学习笔记--Modbus-RTU通讯
笔记·学习·c#
绿浪19846 小时前
async/await 深入学习
学习