Rust 学习笔记:Deref trait

rust笔记8-Deref与隐式解引用强制转换 Rust 的智能指针和 Deref Trait 是 Rust 中非常重要的概念,它们使得 Rust 的引用和指针操作更加灵活和安全。下面我们将深入介绍 Deref Trait、Deref 与 &、* 运算符的关系,以及 Rust 的隐式解引用强制转换(Deref Coercion)。 阅读详情

Rust 学习笔记:Deref trait

实现 Deref trait 允许自定义解引用操作符 * 的行为。

通过实现 Deref trait,智能指针可以像普通引用一样对待。

跟随指针找到值

常规引用是指针的一种类型,将指针理解为指向存储在其他地方的值的箭头。

fn main() {
    let x = 5;
    let y = &x;

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

变量 x 的值是 i32。设 y 等于对 x 的一个引用,可以断言 x 等于 5。然而,如果我们想要对 y 中的值做出断言,我们必须使用 *y 来对 y 解引用,就可以访问 y 所指向的整数值,将其与 5 进行比较。

如果将 y 和 5 进行比较,会报错:不允许比较数字和对数字的引用,因为它们是不同的类型。

像引用一样使用 Box<T>

我们可以重写上一节中的代码,使用 Box<T> 代替引用。

fn main() {
    let x = 5;
    let y = Box::new(x);

    assert_eq!(5, x);
    assert_eq!(5, *y);
}

对 Box<T> 使用的解引用操作符与对引用使用的解引用操作符的作用相同。

两段代码的主要区别在于,这里我们将 y 设置为指向 x 拷贝值的 box 的实例,而不是指向 x 值的引用。

接下来,我们将探讨 Box<T> 的特殊之处,它使我们能够通过定义自己的类型来使用解引用操作符。

定义自己的智能指针

让我们构建一个类似于 Box<T> 的智能指针,以体验默认情况下智能指针与引用的不同行为。然后,我们将研究如何添加使用解引用操作符的功能。

Box<T> 类型最终被定义为具有一个元素的元组结构体,以同样的方式定义了 MyBox<T> 类型。我们还将定义一个 new 函数来匹配在 Box<T> 上定义的 new 函数。

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

fn main() {
    let x = 5;
    let y = MyBox::new(x);
    
    assert_eq!(5, x);
    assert_eq!(5, *y);
}

MyBox 类型是一个包含一个泛型 T 类型元素的元组结构体。MyBox::new 函数接受一个 T 类型的形参,并返回一个 MyBox 实例,该实例保存传入的值。

让我们尝试使用 MyBox 类型,运行上面的代码,结果如下:

在这里插入图片描述

我们的 MyBox<T> 类型不能被解引用,因为我们还没有在我们的类型上实现 Deref trait。

实现 Deref trait

为了实现 trait,我们需要为 trait 所需的方法提供实现。

标准库提供的 Deref trait 要求我们实现一个名为 Deref 的方法,该方法借用 self 并返回对内部数据的引用。

让我们为 MyBox 类型实现 Deref 方法:

use std::ops::Deref;

impl<T> Deref for MyBox<T> {
    type Target = T;
    
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

type Target = T; 语法为 Deref trait 定义了要使用的关联类型。关联类型是声明泛型参数的一种稍微不同的方式。

我们用 &self 填充 deref 方法的主体。因此,deref 返回对要用 * 操作符访问的值的引用,.0 访问元组结构中的第一个值。

没有 Deref trait,编译器只能解引用 & 引用。deref 方法使编译器能够接受实现 Deref trait 的任何类型的值,并调用 deref 方法来获取一个它知道如何解引用的 & 引用。

当我们使用 *y 时,Rust 在幕后实际运行了这段代码:

*(y.deref())

Rust 将 * 操作符替换为对 deref 方法的调用,然后转变为一个普通的解引用。这个 Rust 特性允许我们编写功能相同的代码(都使用 * 解引用),无论我们使用的是常规引用还是实现 Deref trait 的类型。

deref 方法返回一个值的引用,而在 *(y.deref()) 中括号外的普通解引用仍然是必要的,这与所有权系统有关。如果 deref 方法直接返回值而不是对该值的引用,则该值将被移出 self。在这种情况下,或者在大多数使用解引用操作符的情况下,我们不希望获得 MyBox<T> 内部值的所有权。

函数和方法的隐式强制转换

Deref 强制转换将对实现 Deref trait 的类型的引用转换为对另一类型的引用。

例如,Deref 强制转换可以将 &String 转换为 &str,因为 String 实现了 Deref trait,因此它返回 &str。

Deref 强制转换是 Rust 对函数和方法的参数执行的一种便利,并且只对实现了 Deref trait 的类型起作用。当将对特定类型值的引用作为实参传递给与函数或方法定义中的形参类型不匹配的函数或方法时,会自动发生这种情况。对d eref 方法的一系列调用将我们提供的类型转换为参数所需的类型。

在 Rust 中添加了强制转换,这样编写函数和方法调用的程序员就不需要添加那么多带有 & 和 * 的显式引用和解引用。该特性还允许我们编写更多可以用于引用或智能指针的代码。

例如,我们实现了一个 hello 函数,入参 name 是 &str:

fn hello(name: &str) {
    println!("Hello, {name}!");
}

Deref 强制转换使得使用对 MyBox<String> 类型值的引用来调用 hello 函数成为可能。

fn main() {
    let m = MyBox::new(String::from("Rust"));
    hello(&m);
}

这里我们用参数 &m 调用 hello 函数,这是对 MyBox<String> 值的引用。因为我们对 MyBox<T> 实现了 Deref trait, Rust 可以通过调用 deref 方法将 &MyBox<String> 转换为 &String。标准库提供了一个 Deref on String 的实现,它返回一个字符串切片。Rust 再次调用 deref 将 &String 转换为 &str,这与 hello 函数的定义相匹配。

// 转换过程
&MyBox<String> -> &String -> &str

如果 Rust 没有 Deref 强制转换,我们将不得不编写这样的代码,以 &MyBox<String> 类型的值调用 hello 函数。

fn main() {
    let m = MyBox::new(String::from("Rust"));
    hello(&(*m)[..]);
}

(*m) 将 MyBox<String> 解引用为 String,[…] 取整个 String 为字符串切片,& 再次取引用,以匹配 hello 函数的签名。

由于涉及到所有这些符号,这段没有 Deref 强制转换的代码更难读、写和理解。强制转换允许 Rust 自动为我们处理这些转换。

当为所涉及的类型定义了 Deref trait 时,Rust 将分析这些类型,并根据需要多次使用 Deref::deref 来获取与参数类型匹配的引用。需要插入 Deref::deref 的次数是在编译时解决的,所以利用 Deref 强制转换不会造成运行时的损失!

强制转换如何与可变性相互作用

与使用 Deref trait 在不可变引用上重写 * 操作符类似,可以使用 DerefMut trait 在可变引用上重写 * 操作符。

在三种情况下,Rust 在发现类型和 trait 实现时进行强制转换:

  1. 当 T: Deref<Target=U> 时,从&T 到 &U
  2. 当 T: DerefMut<Target=U> 时,从 &mut T 到 &mut U
  3. 当 T: Deref<Target=U> 时,从 &mut T 到 &U

前两种情况是相同的,只是第二种实现了可变性。第一种情况表明,如果你有一个 &T,并且 T 实现了对某种类型 U 的 Deref,你可以透明地获得一个 &U。第二种情况表明,对于可变引用也会发生相同的强制解引用。

第三种情况更棘手:Rust 还会将一个可变引用强制转换为一个不可变引用。但反过来是不可能的,不可变引用永远不会强制到可变引用。

由于借用规则,如果您有一个可变引用,那么该可变引用必须是对该数据的唯一引用(否则,程序将无法编译)。将一个可变引用转换为一个不可变引用永远不会违反借用规则。将不可变引用转换为可变引用将要求初始不可变引用是对该数据的唯一不可变引用,但借用规则不能保证这一点。因此,Rust 不能假设将不可变引用转换为可变引用是可能的。

EPLAN二次开发入门:Visual Studio 2019环境配置与插件调试实战 本文详细介绍了EPLAN二次开发入门的关键步骤,重点讲解如何在Visual Studio 2019中配置开发环境并进行插件调试。通过创建符合命名规范的项目、引用核心API库、实现插件接口以及使用附加进程调试等实战技巧,帮助电气工程师快速掌握EPLAN插件开发,提升自动化设计效率。 阅读详情

相关推荐

C++开发基础之掌握常用的三种异步编程模型

以上是三种常见的C++异步编程模型,每种模型都有其适用的场景和特点。根据具体需求,你可以选择合适的模型来进行异步编程。

dotnet研习社 2175

【Rust 基础篇】Rust Deref Trait 的使用

Sized;Sized:指定解引用操作的目标类型。Target可以是一个具体类型,也可以是一个?Sized的 trait 对象。:定义解引用操作,返回目标类型的引用。通过实现 Deref trait,我们可以重载解引用操作符,使其能够自动调用类型的deref方法进行解引用。本篇博客详细介绍了 Rust 中的 Deref trait 的定义和特性,以及如何实现和使用它。通过实现 Deref trait,我们可以重载解引用操作符,使其在使用时表现得像引用类型。

繁依Fanyi的博客 1314

大学生电赛学习之路

可以看到全国大学生电子设计大赛的认可度是非常高的,属于A类学科竞赛。电子设计大赛的形式也是给出题目,参赛者有四天三夜的时间解决问题,题目大致可以分为:控制类、测量类、高频类以及电力电子类。该竞赛会在单数年的9月份举行。但是对于新生来说电赛确实遥不可及的,可能在很多学校本科生是不能进入实验室的,但是就算进了实验室你就有资格去参加电赛或者说能拿一个不错的奖项吗? 现在正值新生开学季,当然会有一大批学生会进入实验室的学习,电赛的举办时间是每年的暑假,所以说对于大一同学来说有一年的时间去准备,那我们就来说一说参加.

weixin_46098612的博客 8788

我的RUST学习—— 【第十五章 15-2】Deref Trait

Deref Trait 实现 Deref Trait 使我们可以自定义解引用运算符 * 的行为 通过实现 Deref,智能指针可像常规引用一样来处理 解引用运算符 常规的引用也是一种指针! 常规引用下的解引用 let x = 5; let y = &x; let z = *y; // 5 Box 作为引用下的解引用 let x = 5; let y = Box::new(x); let z = *y; // 5 定义自己的智能指针 Box <T> 本质上被定义成 拥有一个元素的

swallowblank的博客 412

RK3568+XS9922B+Android11双模视频输入:CVBS与AHD兼容驱动开发实战

本文详细介绍了基于RK3568平台和XS9922B解码芯片,在Android11系统上开发支持CVBS与AHD双模视频输入的兼容驱动实战。内容涵盖硬件选型、内核驱动框架分析、双模信号自动识别与配置、视频通道切换实现及图像质量优化等关键技术点,为车载监控等需要兼容新旧摄像头的项目提供完整解决方案。

js777的博客 379

MOSS-TTS开源语音合成家族:从架构解析到生产部署实战

语音合成(TTS)技术旨在让计算机将文本转换为自然流畅的语音,其核心原理通常涉及文本分析、声学模型和声码器等模块。近年来,基于深度学习的端到端TTS模型,特别是结合残差向量量化(RVQ)和Transformer架构的方案,显著提升了合成语音的自然度和效率。这类技术的价值在于能够广泛应用于有声内容创作、智能助手、无障碍服务以及实时交互等场景。本文聚焦于开源的MOSS-TTS家族,它通过模块化设计,针对高保真合成、多角色对话、实时交互等不同需求提供了专用模型。文章深入解析了其底层的Delay与Local两种架构

weixin_28745565的博客 419

【Rust】——通过Deref trait将智能指针当作常规引用处理

🎯追踪指针的值 🎯像引用一样使用Box 🎯自定义智能指针 🎯通过实现Deref trait 将某一类型像引用一样处理 🎯函数和方法的隐式Deref强制转换 🎯Deref强制转换如何与可变交互

shsjssnn的博客 2432

【Android14 ShellTransitions】Transition就绪:双Transaction与SurfaceControl显示时机剖析

本文深入剖析了Android14 ShellTransitions框架中Transition就绪阶段的核心机制。重点解释了为何需要“双Transaction”来精确控制SurfaceControl的显示与隐藏时机,以确保Activity切换动画的流畅性。通过分析onTransactionReady流程、窗口绘制状态机及动画目标提升策略,揭示了系统如何协调WMCore与WMShell,实现从状态收集到动画播放的无缝衔接。

ooo22的博客 527

Rust常用特型之Deref和DerefMut特型

Rust常用特型之Deref和DerefMut特型

天草降临的博客 1396

王道考研计算机网络课件全解析:从零搭建你的知识框架(附B站视频+PPT下载)

本文全面解析王道考研计算机网络课程的核心知识体系,从OSI七层模型到TCP/IP四层架构,详细讲解物理层、数据链路层、网络层、传输层和应用层的关键技术。提供高效学习路径、实战案例和常见误区警示,帮助考生系统构建计算机网络知识框架,适合计算机考研备考者参考学习。

leaf8的博客 560

读懂 SAP Fiori Administration Catalogs:从管理员入口、权限编排到 Spaces 和 Pages 的落地实践

SAP Fiori 管理员目录的核心价值在于为系统配置提供标准化入口,解决权限与展示分离的问题。随着 SAP_UI 7.55 版本更新,SAP_FLP_ADMIN 角色整合了关键管理工具(如 Launchpad Designer、Content Manager),并通过 Business Catalog 和 Space 的协同作用,确保管理员既能访问配置工具,又能直观查看相关功能入口。项目实施中需注意配置层级(系统级/客户端级)的选择,以及多人协作时的数据同步问题,以提升交付效率。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 193

Rust 通过 Deref trait 将智能指针当作常规引用处理

为了体会默认情况下智能指针与引用的不同,让我们创建一个类似于标准库提供的Box类型的智能指针。接着学习如何增加使用解引用运算符的功能。从根本上说,Box被定义为包含一个元素的元组结构体,所以示例 15-8 以相同的方式定义了MyBox类型。我们还定义了new函数来对应定义于Box的new函数:文件名: src/main.rsMyBox(x)示例 15-8:定义MyBox类型这里定义了一个结构体MyBox并声明了一个泛型参数T,因为我们希望其可以存放任何类型的值。

m0_52796585的博客 994

PyTorch强化学习实战(1)——强化学习(Reinforcement Learning,RL)详解

在本节中,开始进入探索强化学习 (Reinforcement Learning, RL) 之旅,首先剖析了强化学习的独特之处及其与监督学习、无监督学习范式的关系。随后系统学习了强化学习的基础形式化框架及其内部关联机制,并深入讲解了马尔可夫过程 (Markov Process, MP)、马尔可夫奖励过程 (Markov Reward Process, MRP) 和马尔可夫决策过程 (Markov Decision Process, MDP),为后续学习奠定基础。

盼小辉丶的博客 2050

【Rust自学】15.2. Deref trait Pt.1:什么是Deref、解引用运算符*与实现Deref trait

如果一个类型实现了`Deref` trait,那么它就使我们可以**自定义解引用运算符`*`的行为**。通过实现`Deref` trait,**智能指针可像常规引用一样来处理**。

A Rookie in San Domenico School 1454

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

Rust 语言特性:Deref Trait 和 解引用

Rust中的解引用机制通过Deref trait实现,与C++的指针解引用不同。Rust的引用附加了生命周期、借用规则等安全机制。实现Deref trait的自定义类型(如MyBox)需要通过deref()方法返回内部值的引用,编译器会自动处理解引用操作。强制解引用转换功能允许类型自动转换为目标类型的引用,减少手动使用&和*操作符的需要。转换过程中会保持或收紧引用的可变性,但不会放宽限制。这一机制使智能指针的使用更加简洁安全。

Laurence的技术博客 1102

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

【Rust自学】15.3. Deref trait Pt.2:隐式解引用转化与可变性

隐式解引用转化(Deref Coercion)是为函数和方法提供的一种便捷特性。它的原理是:*假如类型`T`实现了`Deref` trait,那么Deref Coercion可以把`T`的引用转化为`T`经过`Deref`操作后生成的引用。

A Rookie in San Domenico School 1062

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

深入探讨 Rust 中的 Deref Trait:让智能指针像常规引用一样工作

在 Rust 中,引用是非常常见且重要的概念。普通引用(如 `&T`)使用 `*` 运算符进行解引用,允许我们直接访问指向的数据。而智能指针则为数据管理引入了更多的灵活性和功能,比如堆分配、所有权管理等。但是,如果希望让智能指针在使用上更接近普通引用,该如何实现呢?答案就在于 **Deref Trait**。本文将带你详细了解 `Deref` trait 的原理、使用方法以及其背后的隐式解引用转换(deref coercion)机制。

hello.reader 1386

Rust 中 Deref Coercion 介绍

本文介绍了 Rust 中的 Deref Coercion 机制。

aggresss 1149

Rust Design Patterns 之 Deref 多态反模式:滥用 Deref 模拟继承的陷阱与正确替代方案

在 Rust 中,结构体之间不存在继承关系,而许多从 Java、C++ 转入 Rust 的开发者会本能地希望"让子类型复用父类型的方法"。本文基于本仓库 [anti_patterns 章节](https://link.gitcode.com/i/11ff99c9bd46a601295a3bc943abe1fc) 中的 **Deref 多态(Deref polymorphism)反模式**,系统讲解

gitblog_00091的博客 286

Rust 反模式(Anti-patterns)全解析:borrow_clone、deny-warnings 与 Deref 多态的识别与规避

**导读**:本文基于开源仓库 `gh_mirrors/pa/patterns`(Rust Design Patterns 一书)中的 [反模式章节](https://link.gitcode.com/i/2a5556918c546730f665a860e834582f) 及其三篇子文档,系统讲解 Rust 社区公认的三大反模式——「为通过借用检查而盲目 clone」、「在 crate 根用 `#

gitblog_00036的博客 1161

【Rust中级教程】1.16. 泛型trait:泛型(类型参数)trait、关联类型trait

泛型trait要求必须指定所有的泛型类型参数,并重复写这些参数的约束(bounds)。这么写维护起来会难一些。比如说如果添加泛型类型参数到某个trait,该trait的所有实现者都必须更新代码。

A Rookie in San Domenico School 1449

Rust 登堂 之 Deref 解引用(十)

现在,让我们一起来实现一个智能指针,功能上类似 Box<T> 由于 Box<T> 本身很简单,并没有包含类如长度,最大长度等信息,因此用一个元组结构体即可。(5, *y);运行后,报错如下(5, *y);很简单,当解引用 MyBox 智能指针时,返回元组结构体中的元素 &self.0, 有几点要注意的:在 Deref 特征中生命了关联类型 Target ,在之前章节中介绍过,关联类型主要是为了提升代码可读性。

m0_48050264的博客 1199

Rust : 关于Deref

本文介绍了Rust中Deref Trait的核心概念和用法。Deref Trait通过隐式自动解引用来简化代码操作,其核心逻辑是将*T转换为*(T.deref())。文章详细解析了常见的取引用和解引用操作,包括&*T、&**T等组合操作的含义,并重点说明了点操作符.背后隐含的多步自动解引用过程。此外,还介绍了通过Deref实现的类型转换&T到&U的机制,以及这种转换在函数参数传递中的应用场景。理解Deref Trait的自动解引用特性对掌握Rust所有权系统至关重要。

代码过客 475

Rust 的 Deref 强制转换与智能指针自动解引用:编译器帮你省的代码

Sized;Dereftrait 只有一个关联类型Target和一个方法deref()。deref()返回——一个指向内部数据的不可变引用。当编译器遇到*x时,如果x实现了Deref,则*x等价于*x.deref()——先调用deref()获取内部引用,再解引用获取值。/// 自定义智能指针:带引用计数的智能指针(简化版 Rc)value: T,count: 1,value,}));/// 获取引用计数// 通过 Deref 强制转换,MyRc<T> 可以像 &T 一样使用。

no1coder的博客 4718

Rust 练习册 4:Deref trait 与智能指针

Rust的Deref特性用于自定义解引用运算符(*)的行为,使智能指针能像常规引用一样使用。通过实现Deref trait定义关联类型Target和deref方法即可创建智能指针类型。Deref强制转换能自动将&T转换为&U(当T实现Deref<Target=U>时),这在函数调用和智能指针(如Rc、RefCell)中非常实用。配合DerefMut还可重载可变解引用。示例展示了自定义智能指针、引用计数和内部可变性等应用场景,体现了Rust类型系统的灵活性和表达能力。

少湖说 341

【Rust中级教程】2.4. API设计原则之不意外性(unsurprising) Pt.4:“人体工程学”的trait实现、包装类型(Wrapper Types)、`Borrow` trait

对于迭代器来说,如果某个类型可以迭代,那么它的引用也应该添加相应的trait实现。也就是说:**对于任何可迭代的类型,考虑为`&MyType`和`&mut MyType`实现`IntoIterator`**。这样在循环中我们就可以直接使用借用的实例,符合用户预期。

A Rookie in San Domenico School 1221
上一篇: Rust 学习笔记:Box<T>
下一篇: Rust 学习笔记:关于智能指针的练习题
UestcXiye
博客等级 码龄8年 9028粉丝 1306原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UestcXiye

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值