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

💻博主现有专栏:

                C51单片机(STC89C516),c语言,c++,离散数学,算法设计与分析,数据结构,Python,Java基础,MySQL,linux,基于HTML5的网页设计及应用,Rust(官方文档重点总结),jQuery,前端vue.js,Javaweb开发,Python机器学习等
🥏主页链接:

                Y小夜-CSDN博客

目录

🎯追踪指针的值

🎯像引用一样使用Box

🎯自定义智能指针

🎯通过实现Deref trait 将某一类型像引用一样处理

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

🎯Deref强制转换如何与可变交互


        实现 Deref trait 允许我们重载 解引用运算符dereference operator*(不要与乘法运算符或通配符相混淆)。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。

        实现 Deref trait 允许我们重载 解引用运算符dereference operator*(不要与乘法运算符或通配符相混淆)。通过这种方式实现 Deref trait 的智能指针可以被当作常规引用来对待,可以编写操作引用的代码并用于智能指针。

🎯追踪指针的值

        常规引用是一个指针类型,一种理解指针的方式是将其看成指向储存在其他某处值的箭头。在示例 15-6 中,创建了一个 i32 值的引用,接着使用解引用运算符来跟踪所引用的值:

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

        变量 x 存放了一个 i32 值 5y 等于 x 的一个引用。可以断言 x 等于 5。然而,如果希望对 y 的值做出断言,必须使用 *y 来追踪引用所指向的值(也就是 解引用),这样编译器就可以比较实际的值了。一旦解引用了 y,就可以访问 y 所指向的整型值并可以与 5 做比较。

🎯像引用一样使用Box<T>

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

        将 y 设置为一个指向 x 值拷贝的 Box<T> 实例,而不是指向 x 值的引用。在最后的断言中,可以使用解引用运算符以 y 为引用时相同的方式追踪 Box<T> 的指针。接下来让我们通过实现自己的类型来探索 Box<T> 能这么做有何特殊之处。

🎯自定义智能指针

        为了体会默认情况下智能指针与引用的不同,让我们创建一个类似于标准库提供的 Box<T> 类型的智能指针。接着学习如何增加使用解引用运算符的功能。

        从根本上说,Box<T> 被定义为包含一个元素的元组结构体

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

        这里定义了一个结构体 MyBox 并声明了一个泛型参数 T,因为我们希望其可以存放任何类型的值。MyBox 是一个包含 T 类型元素的元组结构体。MyBox::new 函数获取一个 T 类型的参数并返回一个存放传入值的 MyBox 实例。

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

得到的编译错误是:

$ cargo runCompiling deref-example v0.1.0 (file:///projects/deref-example)
error[E0614]: type `MyBox<{integer}>` cannot be dereferenced--> src/main.rs:14:19|
14 |     assert_eq!(5, *y);|                   ^^For more information about this error, try `rustc --explain E0614`.
error: could not compile `deref-example` due to previous error

   MyBox<T> 类型不能解引用,因为我们尚未在该类型实现这个功能。为了启用 * 运算符的解引用功能,需要实现 Deref trait。

🎯通过实现Deref trait 将某一类型像引用一样处理

        为了实现 trait,需要提供 trait 所需的方法实现。Deref trait,由标准库提供,要求实现名为 deref 的方法,其借用 self 并返回一个内部数据的引用。示例 15-10 包含定义于 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; 语法定义了用于此 trait 的关联类型。

        没有 Deref trait 的话,编译器只会解引用 & 引用类型。deref 方法向编译器提供了获取任何实现了 Deref trait 的类型的值,并且调用这个类型的 deref 方法来获取一个它知道如何解引用的 & 引用的能力。

*(y.deref())

        Rust 将 * 运算符替换为先调用 deref 方法再进行普通解引用的操作,如此我们便不用担心是否还需手动调用 deref 方法了。Rust 的这个特性可以让我们写出行为一致的代码,无论是面对的是常规引用还是实现了 Deref 的类型。

   deref 方法返回值的引用,以及 *(y.deref()) 括号外边的普通解引用仍为必须的原因在于所有权。如果 deref 方法直接返回值而不是值的引用,其值(的所有权)将被移出 self。在这里以及大部分使用解引用运算符的情况下我们并不希望获取 MyBox<T> 内部值的所有权。

        注意,每次当我们在代码中使用 * 时, * 运算符都被替换成了先调用 deref 方法再接着使用 * 解引用的操作,且只会发生一次,不会对 * 操作符无限递归替换,解引用出上面 i32 类型的值就停止了,这个值与示例 15-9 中 assert_eq! 的 5 相匹配。

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

        Deref 强制转换deref coercions)将实现了 Deref trait 的类型的引用转换为另一种类型的引用。例如,Deref 强制转换可以将 &String 转换为 &str,因为 String 实现了 Deref trait 因此可以返回 &str。Deref 强制转换是 Rust 在函数或方法传参上的一种便利操作,并且只能作用于实现了 Deref trait 的类型。当这种特定类型的引用作为实参传递给和形参类型不同的函数或方法时将自动进行。这时会有一系列的 deref 方法被调用,把我们提供的类型转换成了参数所需的类型。

        Deref 强制转换的加入使得 Rust 程序员编写函数和方法调用时无需增加过多显式使用 & 和 * 的引用和解引用。这个功能也使得我们可以编写更多同时作用于引用或智能指针的代码。

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

        当所涉及到的类型定义了 Deref trait,Rust 会分析这些类型并使用任意多次 Deref::deref 调用以获得匹配参数的类型。这些解析都发生在编译时,所以利用 Deref 强制转换并没有运行时损耗!

🎯Deref强制转换如何与可变交互

        类似于如何使用 Deref trait 重载不可变引用的 * 运算符,Rust 提供了 DerefMut trait 用于重载可变引用的 * 运算符。

  • 当 T: Deref<Target=U> 时从 &T 到 &U
  • 当 T: DerefMut<Target=U> 时从 &mut T 到 &mut U
  • 当 T: Deref<Target=U> 时从 &mut T 到 &U

        头两个情况除了第二种实现了可变性之外是相同的:第一种情况表明如果有一个 &T,而 T 实现了返回 U 类型的 Deref,则可以直接得到 &U。第二种情况表明对于可变引用也有着相同的行为。

        第三个情况有些微妙:Rust 也会将可变引用强转为不可变引用。但是反之是 不可能 的:不可变引用永远也不能强转为可变引用。因为根据借用规则,如果有一个可变引用,其必须是这些数据的唯一引用(否则程序将无法编译)。将一个可变引用转换为不可变引用永远也不会打破借用规则。将不可变引用转换为可变引用则需要初始的不可变引用是数据唯一的不可变引用,而借用规则无法保证这一点。因此,Rust 无法假设将不可变引用转换为可变引用是可能的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/1663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

分享购热潮席卷而来:解析其背后的成功密码

亲爱的朋友们&#xff0c;我是微三云的周丽&#xff0c;一名专注于私域电商模式创新的探索者。 随着数字化时代的到来&#xff0c;消费者的购物行为也在不断变化&#xff0c;因此&#xff0c;企业必须不断地探索新的ying销方式&#xff0c;以xi引用户、提升xiao售额。而最近备…

SVN泄露(ctfhub)

目录 下载安装dvcs-ripper 使用SVN 一、什么是SVN&#xff1f; 使用SVN能做什么&#xff1f; 二、SVN泄露&#xff08;ctfhub&#xff09; SVN源代码漏洞的主要原因&#xff1a; 工具准备&#xff1a;dirsearch、dvcs-ripper 网络安全之渗透测试全套工具篇&#xff08;内…

asrpro 启动流程

学术用途&#xff0c;无意冒犯&#xff0c;如有冒犯&#xff0c;敬请告之&#xff0c;侵删 使用vscode 打开&#xff0c;设置断点&#xff0c;查看启动过程&#xff0c;文档中代码有详细的注释 运行语音程序 触发程序 system_hook.c ASR_CODE 事件发生时调用 system_hook.…

深入理解VGG网络,清晰易懂

深入理解VGG网络 VGG网络是深度学习领域中一个非常经典的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;由牛津大学的视觉几何组&#xff08;Visual Geometry Group&#xff09;提出。它在2014年的ImageNet挑战赛中取得了第二名的好成绩&#xff0c;并且在随后的许…

智慧水务能效管理系统平台/地下污水厂配电系统电气安全设计

安科瑞电气薛瑶瑶18701709087 1、引言 地下水污厂在城市建设中扮演着重要的角色,负责对城市污水和废物进行处理和排放。然而,由于地下水污厂中存在着许多危险因素,如有害气体、液体和固体废物等,因此要保证电气安全。电气安全系统是地下水污厂安全生产的重要保障措施之一,包括…

C语言进阶课程学习记录-函数参数的秘密

C语言进阶课程学习记录-函数参数的秘密 实验实验小结调用约定实验-求平均数实验-可变参数的函数小结 本文学习自狄泰软件学院 唐佐林老师的 C语言进阶课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 实验 #include <stdio.h>int func(int i, int…

MySQL学习笔记1(MySQL基础)

1.MySQL基础 1.数据库相关概念 ​ *数据库&#xff1a;存储数据的仓库&#xff0c;数据是有组织的进行存储 DtaBase(DB) ​ *数据管理系统&#xff1a;操纵和管理数据库的大型软件 DataBase Management System (DBMS) ​ *SQL&#xff1a;操作关系型数据库的编程语言&#…

初始C++

1. C关键字(C98) C总计63个关键字&#xff0c; C语言32个关键字 ps&#xff1a;下面我们只是看一下C有多少关键字&#xff0c;不对关键字进行具体的讲解。后面我们学到以后再 细讲。 2. 命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;…

JAVA学习笔记28(常用类)

1.常用类 1.1 包装类 1.包装类的分类 ​ 1.针对八中基本数据类型相应的引用类型–包装类 ​ 2.有了类的特点&#xff0c;就可以调用类中的方法 2.包装类和基本数据类型的转换 ​ *装箱&#xff1a;基本类型 --> 包装类型 //手动装箱 int n1 100; Integer integer ne…

【C语言__函数栈帧的创建和销毁__复习篇9】

目录 前言 一、知识补充 二、分析创建和销毁的过程 三、前言问题回答 前言 本篇主要讨论以下问题&#xff1a; 1. 编译器什么时候为局部变量分配的空间 2. 为什么局部变量的值是随机的 3. 函数是怎么传参的&#xff0c;传参的顺序是怎样的 4. 形参和实参是什么关系 5. 函数…

电商平台业务及架构演变史

不少人认为电商系统很简单&#xff0c;因为现在做电商的太多了&#xff0c;看到的电商产品也多。看来看去产品都差不多&#xff0c;没什么特别。 其实中国电商发展已有20多年历史&#xff0c;电商以销售为核心连接着研、产、供、销、服整套的信息系统体系。其中的设计并没有那…

企业公众号数量怎么申请

一般可以申请多少个公众号&#xff1f;许多用户在申请公众号时可能会遇到“公众号显示主体已达上限”的问题。这是因为在2018年11月16日对公众号申请数量进行了调整&#xff0c;具体调整如下&#xff1a;1、个人主体申请公众号数量上限从2个调整为1个。2、企业主体申请公众号数…

vue---计算属性

姓名案例 1.使用插值语法实现 <!DOCTYPE html> <html><head><meta charset"UTF-8" /><title>姓名案例_插值语法实现</title><!-- 引入Vue --><script type"text/javascript" src"../js/vue.js"&g…

从源码选择到国际化运营:打造成功的跨境电商网站必备指南

跨境电商网站的成功离不开经过精心策划和执行的全面计划。从源码选择到国际化运营&#xff0c;每一步都至关重要。作为跨境电商领域的专家&#xff0c;我将为您提供打造成功跨境电商网站的必备指南&#xff0c;帮助您开拓全球市场&#xff0c;提升边际收入。 选择优质的跨境电…

云服务器ECS选型知多少

云服务器ECS选型知多少 ECS产品规格如何选择实例规格变配 说到云服务器ECS选型&#xff0c;那可以说太重要了。因为对于一个项目来说&#xff0c;从项目到开始到最后的部署上线&#xff0c;每一步都需要付出&#xff0c;这些对于企业或者个人来说都是一笔投入&#xff0c;那么如…

会议预告 | 易基因与您相约2024中国衰老科学大会(附日程) 新品首发

由中国细胞生物学学会衰老细胞生物学分会等单位联合主办&#xff0c;瓯江实验室、温州医科大学老年研究院等共同承办的2024中国衰老科学大会暨国际衰老生物学大会将于2024年4月26日-28日在温州召开。本次大会以“解码衰老”为主题&#xff0c;旨在汇聚全球科研精英&#xff0c;…

全开源商城源码后台php全端uniapp 全开源可二开 功能强大 商城系统源码

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 内置8中搭配主色(可自行扩展更多配色)、自由快捷切换适应各大行业需求 已支持小程序&#xff08;微信、QQ、百度、支付宝、头条&抖音、快手&#xff09; H5 APP App.vue中修改 r…

Vue 3响应式系统全解析:深入ref、reactive、computed、watch及watchEffect

一、ref与breactive 宏观角度看&#xff1a; 1.ref 用来定义:基本类型数据、对象类型数据&#xff1b;2.reactive 用来定义:对象类型数据。 区别&#xff1a; 【ref 】创建的变量必须使用.value 。【reactive】 重新分配一个新对象&#xff0c;会失去响应式(可以使用0biect…

EasyMR6.2 全面解读:四大功能深度优化,解锁全新大数据处理和计算体验

在刚刚过去的2024春季发布会上&#xff0c;袋鼠云带来了数栈产品V6.2版本的全新发布。其中&#xff0c;EasyMR 作为数栈V6.2中的一项关键能力&#xff0c;代表了袋鼠云对大数据生态的深入理解和持续创新。 EasyMR&#xff08;后文统称EMR&#xff09;是袋鼠云基于 Hadoop、Hiv…

游戏系统设计目录

《游戏系统设计0》跟我一起做游戏服务器《游戏系统设计一》游戏任务系统太复杂,带你一步一步实现 《游戏系统设计二》操蛋,游戏版本要回滚,还好我机智备份了数据库,代码直接拿走《游戏系统设计三》游戏服务器线上出bug,怎么办?急,在线等!热更新