gm怎么刷东西 rust_Rust语言:解引用详述,搞不明白这个概念,趁早放弃Rust

737336bf04d6259c54ed8ffe50b4fe82.png

Rust是内存安全的,对新手来说,最大的困难是可恶的编译器,在其他语言上面叱咤风云,偏偏被Rust搞到崩溃。所以,大家都戏谑道,Rust是面向编译器编程。

和编译器做斗争的过程中,遇到最多的是,变量所有权被move了,某个api需要传入可变引用而我却不知道如何获取。

只要你了解了如何解引用,如何做类型转换,这些问题都将迎刃而解。

0e2c70f0e08fa0e0ccbc19aba04f8789.png

什么是解引用

引用是对内存块的借用,Rust里每一个内存块都是有主人的,主人就是对内存拥有所有权的变量,没有主人的内存块我们称之为内存泄露了。

解引用是通过引用找到内存块真正的主人,然后你可以跟主人借一些不同类型的引用,比如从&mut T借成Pin<&mut T>。

这个主人可能被包了很多层,当你以为你找了主人,其实它只是个皮,所以会存在不断解引用的情况,你可能需要加很多个*,当然很多个*不符合设计美感。

Rust语法规定,同一块内存只能有一个可变引用,或者有多个不可变引用。这给习惯于C++或者Java等语言的编程人员造成了很大的困扰,违反了多年以来养成的编程习惯,特别的别扭,因为他们眼中元原本的理解是所有的引用都是可变引用。

Rust之所以这么规定,一个非常大的优点是避免了内存被多处修改的潜在隐患,避免了资源的复杂环境竞争,降低了程序的调试难度。

那么,程序编写过程中必然会在不同的函数块里调用同一块内存,所以引用的使用将会变得非常频繁,我们犯的错误大多也在此。

解引用的方法

解引用可以分为,自动解引用和手动解引用。

Rust为了减少某些场合下重复解引用导致的代码美观问题,在编译期做了一些智能识别功能,比如带有&T参数的函数被调用的时候,你传&&&......&&&T都可以自动解引用,直到符合函数的参数类型为止。

手动解引用,就是和其他语言类似,借用是&操作符,解引用是*操作符。

我们也可以通过自行实现Deref这个Trait来自定义解引用的最终目标是什么,而恰恰这个也是Rust语言最难的地方,你得了解每个类型是否实现了Deref,而Rust类型实在是太多了,连&T借用也算一个新的类型,&T是不能继承T的所有特性的。

如果想要学好Rust,对Deref不做深入的研究,将会死的很难看。

解引用进阶篇

1、手动实现Deref

Rust已经为所有的&T和&mut T的类型默认实现了简陋版的Deref,解引用就是得到T本身。

当然我们也可以给类型T本身添加一个Deref,这样T本身就可以被接引用,相当于T也是一个引用类型,其实T不是。

下面这个短暂的动态图片形象的阐述了Deref是如何自定义的,以及遇到类型不匹配的函数时,Rust是会自动解引用直到类型匹配为止。

ec18aad0395837fb92c19502f555f4d3.png

2、以Pin<P>为例子,来谈谈解引用

如果P没有实现Deref,即P不可以解引用,那么Pin<P>是不能被*操作符操作的。

当P实现了Deref,那么*Pin<P>的解引用会先触发P解引用操作,得到P的Target的引用,再使用*操作符,最终的结果是P的Target被返回了。然而Pin<P>本身使用deref()得到的是&Target。

所有实现Deref的类型,使用deref函数得到的结果,肯定是一个引用类型。

*操作符为了更通用和方便,原理就是将被解引用的对象,先使用deref调用一下,再解引用。

项目中,最常遇见的是Pin<&mut T>,我们希望得到T的Target的可变引用,一般使用&mut **Pin<&mut T>。如果不了解它是怎么执行的,那么肯定会很疑惑,这个结果是啥。

84c43ec6be29beeba0b56d65f7f7c5bb.png

3、Option<T>如何得到T的Target引用

大多数情况下,我们得到的是Option<T>,可是我们想调用的函数需要传入&T或者T的Target引用,这样就会很疑惑,该怎么得到这个&T呢?

这里也涉及到几个类型的deref函数的调用,首先是要把Option<T>转化为Option<&T>,然后再将T转化为Target引用,如Option.as_ref().map(|s| { s.deref()}),或者直接使用Option自带的as_deref()。

021b5c2126c1b85497b5c5d486ce13b2.png

4、Box<T>是个特例

严格说Box这个语法在Rust里是特权一般的存在,各种小后门开的不亦乐乎。

Box<T>在实现Deref这个Trait时,竟然使用的是&**语法,可是*操作符必须作用在实现Deref的类型上,这到底是先有的鸡,还是先有的蛋呢?

所以,不需要纠结这种被Rust开洞的特例,会使用即可。

4a7a84b49299fdc3633383270547c530.png

写在最后

*操作符的特性是,先将作用对象进行deref得到一个引用,再将&引用清除。如果只是想得到一个引用,那么使用&*或者deref()。

如果不好理解,可以这么去记忆:*是用来消除&和box符号的,当发现目标没有&和box,就会调用deref函数去生成带有&符号的类型,然后就可以愉快的消除了。

掌握好这个技巧,在遇到各种&和*操作符的时候,才不至于被迷惑,找不到深层次的代码的实现原理。

如果你对技术也有追求,对现实迷茫,请关注我,带你一起学习成长。

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

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

相关文章

VS2010中使用gtest简单案例

1、下载googletest代码 https://github.com/google/googletest 2、解压并进入找到msvc文件夹 googletest-master\googletest-master\googletest\msvc 3、打开gtest.sln文件 4、编译gtest和gtest_main工程&#xff0c;生成gtestd.lib和gtest_maind.lib&#xff0c;将这两个静…

记录一次Oracle注入绕waf

这个注入挺特殊的&#xff0c;是ip头注入。我们进行简单的探测: 首先正常发起一次请求&#xff0c;我们发现content-type是76 探测注入我习惯性的一个单引号: 一个单引号我发现长度还是76 我开始尝试单引号&#xff0c;双引号一起: 我失败了长度还是76 一般sql注入输入单引号一…

生成字节码

在这篇文章中&#xff0c;我们将看到如何为我们的语言生成字节码。 到目前为止&#xff0c;我们已经看到了如何构建一种语言来表达我们想要的东西&#xff0c;如何验证该语言&#xff0c;如何为该语言构建编辑器&#xff0c;但实际上我们仍然无法运行代码。 是时候解决这个问题…

Java迭代器contains的问题

功能&#xff1a;ArrayList去除集合中字符串的重复值(字符串的内容相同)&#xff0c;思路&#xff1a;创建新集合方式。 第一种编译运行没问题&#xff0c;第二种写法出错&#xff0c;原因是不可以两次使用it.next()。 错误提示&#xff1a;Exception in thread "main&q…

ad如何镜像器件_使用 Dockerfile 制作镜像

前面几篇文章已经给大家介绍了 Docker 的基本概念&#xff0c;相信大家也会使用 Docker 运行自己想要的容器了。但是只有学会制作镜像&#xff0c;才能将 Docker 应用到我们的项目中去。下面我们就来学习如何使用 Dockerfile 来制作镜像。Dockerfile 是一个文本文件&#xff0c…

centos7.5部署ELk

第1章 环境规划 1.1 ELK介绍 ELK是ElasticSerach、Logstash、Kibana三款产品名称的首字母集合&#xff0c;用于日志的搜集和搜索。 Elasticsearch&#xff1a;是一个开源分布式搜索引擎&#xff0c;提供搜集、分析、存储三大功能&#xff0c;特点是分布式、零配置、自动发…

使用Google Test的一个简单例子

0. 引子 本例是从 gtest-1.5.0 自带的 sample 中的 sample1 改写而来&#xff0c;笔者只添加了一个求 n 的阶层的函数&#xff0c;如下。 void Factorial(int n, int & result ) { result 1; for (int i 1; i < n; i) result * i; } 目的是想测试像这样将返回值放在参…

Java静态方法与非静态方法的泛型

Java中&#xff0c;非静态方法可以使用类的泛型&#xff0c;也可以定义自己的泛型&#xff1b;静态方法由于随着类的加载而加载&#xff0c;不能访问类的泛型&#xff08;因为在创建对象的时候才确定&#xff09;&#xff0c;因此必须定义自己的泛型类型。 详细请参考&#xf…

Android Studio 日志工具

在项目中提供5个方法打印日志 Log.v() 最常见的日志信息 Log.d() 调试信息 Log.i() 用于打印用户操作行为 Log.w()警告潜在风险 Log.e()报错信息 TAG 填入类名就好 msg:要打印的信息 也可以对信息进行过滤 点他弹出自定义的日志过滤器 转载于:https://www.cnblogs.com/feizianq…

jpa加密_使用JPA侦听器的数据库加密

jpa加密最近&#xff0c;我不得不将数据库加密添加到一些字段中&#xff0c;并且发现了很多不好的建议。 建筑问题 最大的问题是建筑。 如果持久性管理器静静地处理您的加密&#xff0c;那么根据定义&#xff0c;您的体系结构将在持久性和安全性设计之间要求紧密而不必要的绑…

同一进程中的线程究竟共享哪些资源

线程共享的环境包括&#xff1a;进程代码段、进程的公有数据(利用这些共享的数据&#xff0c;线程很容易的实现相互之间的通讯)、进程打开的文件描述符、信号的处理器、进程的当前目录和进程用户ID与进程组ID。 进程拥有这许多共性的同时&#xff0c;还拥有自己的个性。有了这些…

物联lot是什么意思_什么是物联网,物联网(lOT)简介

什么是物联网物联网(The Internet of Things&#xff0c;简称IOT)是指通过各种信息传感器、射频识别技术、全球定位系统、红外线感应器、激光扫描器等各种装置与技术&#xff0c;实时采集任何需要监控、 连接、互动的物体或过程&#xff0c;采集其声、光、热、电、力学、化 学、…

Python 位操作运算符

&按位与运算符&#xff1a;参与运算的两个值,如果两个相应位都为1,则该位的结果为1,否则为0(a & b) 输出结果 12 &#xff0c;二进制解释&#xff1a; 0000 1100|按位或运算符&#xff1a;只要对应的二个二进位有一个为1时&#xff0c;结果位就为1。(a | b) 输出结果 6…

JavaOne 2016后续活动

我很高兴今年参加了JavaOne&#xff0c;我可以用一个词概括一下这一经验&#xff1a;Brilliant。 对于我来说&#xff0c;今年与往年相比有很大不同&#xff0c;因为我在周日有一个演讲要共同演讲&#xff0c;而我剩下的一周时间都可以参加会议。 因此&#xff0c;我了解到在Ja…

python对初学者的看法_python学习之道(1)——新手小白对print()函数的理解,Python,之路,一,浅谈...

Python学习之路(一) ——浅谈新手小白对print()函数的理解写在前面笔者目前为在校大四学生(某末流211)&#xff0c;大学生活即将画上终点&#xff0c;然而却还没有真正精通一门语言&#xff0c;很是惭愧。在大学期间参加了各种文体活动&#xff0c;获得了很多次演讲比赛的奖项&…

理解Windows内核模式与用户模式

&#xfeff;&#xfeff;1、基础 运行 Windows 的计算机中的处理器有两个不同模式&#xff1a;“用户模式”和“内核模式”。根据处理器上运行的代码的类型&#xff0c;处理器在两个模式之间切换。应用程序在用户模式下运行&#xff0c;核心操作系统组件在内核模式下运行。多个…

判断使用设备是PC还是phone

<script type"text/javascript"> //如果是手机设备&#xff0c;则.. if(/Android|webOS|iPhone|iPod|BlackBerry/i.test(navigator.userAgent)) {window.location.href "http://www."; } </script><style type"text/css"> me…

求1+2+3+...+n

题目描述 求123...n&#xff0c;要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句&#xff08;A?B:C&#xff09;。 1、根据基本公式展开&#xff0c;利用java的幂函数代替乘法&#xff0c;利用位移运算代替除法 public class Solution {pub…

1 京东_推荐好友拿好礼 | 每1积分可兑换30元京东电子卡

三季度转推介活动火热进行中该积分最终以被推荐客户9月30日金融资产余额为依据积分兑现时间为活动结束后15个工作日我行会将京东电子卡密码通过短信方式直接发送至推荐客户预留手机号码上(请推荐客户登记真实、准确的电话号码&#xff0c;否则无法兑现积分奖励)尊敬的客户&…

在cmd命令行下编译运行C/C++源文件

一直用java来写程序&#xff0c;java配置好jre路径之后&#xff0c;在cmd下编译运行&#xff0c;很方便。 刚好要给一个舍友改下C程序&#xff0c;想到可不可以像java一样在环境变量里配置好C的编译路径呢&#xff1f; 于是上网搜了一下&#xff0c;得到如下结果&#xff1a; 一…