Rust 模式匹配中的 和 ref

news/2024/5/13 9:05:26

一、Rust & 和 ref

1.Rust的ref有什么用

根据Rust官方文档https://doc.rust-lang.org/std/keyword.ref.html

Rust ref 主要用在模式匹配match的所有权问题中。

ref在 Rust中,也是声明一个指针类型变量,进一步说明ref和&在其它方面区别,我们下一篇再说。

Rust的模式匹配,可以发生在函数参数match

  1. 函数参数
fn foo(x: String) {//String::from("test")的所有权已经移交给了xprintln!("{}",x);// 代码
}fn main() {let mut s=String::from("test");foo(s);println!("{}",s);//s的所有权已经丢失,所以不能使用了,此处出错
}

特别注意一下,函数传参也会交出所有权
2.match

fn main() {let x = String::from("test");match x {y => println!("{}", y),// String::from("test")的所有权移动给了y_ => println!("Default case, x = {:?}", x),}println!("at the end: x = {:?}", x);//x的所有权已经丢失,不能再使用。
}

特别注意一下,match的模式匹配是会交出所有权的。

除了使用&引用借用来避免交出所有权的问题,在模式匹配中,我们可以使用**&或ref**来避免交出所有权,match中的ref不再遵循借用规则。那么前面的代码我们可以修改为。

  1. 函数参数使用**&避免**交出所有权
fn foo(x: &mut String) {//println!("{}",x);// 代码
}fn main() {let mut s=String::from("test");foo(&mut s);//(可变/不可变)引用,不拥有所有权println!("{}",s);
}

代码运行通过

    Finished release [optimized] target(s) in 0.20sRunning `target/release/world_hello`
test
test

2、match使用ref避免交出所有权

fn main() {let x = String::from("test");match x {ref y => println!("{}", y),// 其实在match中,不是定义一个变量,而是声明一个变量,ref是进一步声明,y是一个引用,但是不能够&y,因为我们不能够在match中声明y的具体类型。_ => println!("Default case, x = {:?}", x),}println!("at the end: x = {:?}", x);
}

代码运行通过

    Finished release [optimized] target(s) in 0.20sRunning `target/release/world_hello`
test
test

其实这里你可能会问,为什么在match中,不使用&借用避免所有权移动的问题,这是因为match本身机制导致的。

在match中,我们没有机会声明变量类型,不能用&修饰匹配的变量

当然,你非要在**match使用&**来避免移交所有权的问题,我们可以这样做

fn main() {let x = String::from("test");match &x {//将引用定义在这里y => println!("{}", y),//这里不能够写成&y => println!("{}", y),_ => println!("Default case, x = {:?}", x),}println!("at the end: x = {:?}", x);
}

代码运行也是成功的

    Finished release [optimized] target(s) in 0.22sRunning `target/release/world_hello`
test
at the end: x = "test"

我们再来看一个骚的


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match r {&mut value => value.push_str(" world!") }
}

前面我们说了 ,我们不能声明匹配变量,也就是value,那么**&mut 是肯定不能用**的,其实第一版修改,我们可以改成


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match r {value => value.push_str(" world!") //这样其实value就是可变引用,但是&mut v本身的所有权被value拿走了}
}

根据代码注释,如果我们稍加修改就会发现问题


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match r {value => value.push_str(" world!") }println!("{}",r);
}

运行代码

error[E0382]: borrow of moved value: `r`--> src/main.rs:11:17|
6  |   let r = &mut v;|       - move occurs because `r` has type `&mut String`, which does not implement the `Copy` trait
...
9  |      value => value.push_str(" world!") |      ----- value moved here
10 |   }
11 |   println!("{}",r);|                 ^ value borrowed here after move

这里说了,&mut v的所有权被value拿走了

那我不想被value拿走,我们应该怎么做,那么这时候ref的作用就来了,我们可以这么修改

// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match *r {//注意这里是*r,因为r本身就是&str,如果传下去r,ref r 就变成了双重引用,不符合题意ref mut value => value.push_str(" world!") //此时value就是&str类型,但是这不是引用类型}println!("{}",r);
}

运行代码

    Finished release [optimized] target(s) in 0.34sRunning `target/release/world_hello`
hello, world!

前面我们说了,ref不遵循借用的那一套规则,所以上面的代码是可以运行成功的。

按照正常思路的话(假设),按道理应该是两个可变引用,是违背借用原则的,会不会是match{}框住了value的作用域导致,其实只有一个可变引用?

那我们在看一段代码


// 修复错误,尽量少地修改代码
// 不要移除任何代码行
fn main() {let mut v = String::from("hello,");let r = &mut v;match *r {ref mut value => {value.push_str(" world!") ;println!("{}",r);}}println!("{}",r);
}

运行一下

    Finished release [optimized] target(s) in 0.21sRunning `target/release/world_hello`
hello, world!
hello, world!

哈哈,我们已经验证完了

ref不遵循借用的那一套规则,在match的模式匹配中,ref也可以是不拿所有权的一种引用方法。


http://www.mrgr.cn/p/10568168

相关文章

探索项目管理系统:解析五大功能,洞悉项目成功的关键

项目管理新手往往喜欢埋头苦干,殊不知优秀的项目经理已经熟练运用项目管理系统,让项目规划条理清晰。项目管理系统具备的功能,好用的项目管理系统都有这5大功能。分别是项目WBS分解、项目图表和报表、工时管理、团队协作、任务流程自动化。一、项目WBS分解 1.什么是项目WBS分…

PotatoPie 4.0 实验教程(26) —— FPGA实现摄像头图像拉普拉斯锐化

为什么要对图像进行拉普拉斯锐化 对图像进行拉普拉斯锐化的目的是增强图像的边缘和细节,使图像看起来更加清晰和锐利。这种技术常用于图像处理中,具体原因如下: 增强图像的边缘信息:拉普拉斯锐化可以突出图像中的边缘特征&#x…

适用于Windows和Mac的十大误删除数据恢复软件

数据恢复是从辅助存储或可移动文件中找回丢失、删除或损坏的数据的过程。数据丢失的原因有很多。因此,有必要恢复已删除的数据。有各种可用的软件工具,使用户能够恢复任何类型的已删除数据。但是,任何数据恢复都有四个主要阶段。他们正在修复…

CRM软件功能大揭秘:商业利器的多面功效与应用

一、 什么是CRM软件? CRM软件是指一款可以让企业利用相应的信息技术和互联网技术,协调企业与客户在销售、营销和服务方面的互动,提高其管理模式,为客户提供创新的个性化客户互动和服务的软件。使用CRM软件最终目标是吸引新客户,保留老客户,将现有客户转化为忠实客户,增加…

最近常用的几个【行操作】的Pandas函数

最近在做交易数据的统计分析时,多次用到数据行之间的一些操作,对于其中的细节,简单做了个笔记。 1. shfit函数 shift函数在策略回测代码中经常出现,计算交易信号,持仓信号以及资金曲线时都有涉及。这个函数的主要作用是将某列的值上下移动。默认情况下,shift函数是向下移…

在电脑桌面上制作可视化进度日程待办清单,效率翻倍

对于使用电脑办公的上班族来说,提升工作效率和保证任务的准时完成是至关重要的。在电脑桌面上制作可视化进度日程待办清单,是实现这一目标的有效方法。因为这样能够让我们一目了然地了解当天及未来的工作任务,从而合理规划时间,确保每个任务都能得到妥善处理。 那么我们如何…

Chrome扩展 邮件菜单在指定网站显示

chrome.contextMenus | API | Chrome for Developers chrome-extensions-samples/api-samples/contextMenus at main GoogleChrome/chrome-extensions-samples GitHub

差分包制作

1. 版本1; 将第一次编译产生的差分包:target_file 放置于代码根目录(和out 目录同级);并重命名为 ota 1 2.版本 2; 修改build文档,第二次编译产生产分包:target_file 放置于代码根目录(和out 目录同级);并重命名为 ota 2 3.指令:./build/tools/releasetools/ota_fr…

Java 网络编程之TCP(五):分析服务端注册OP_WRITE写数据的各种场景(二)

接上文 二、注册OP_WRITE写数据 服务端代码: import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.S…

Android Monkey工具介绍与使用

过于爽快的承认失败,就可能发觉不了曾经与正确非常接近。大家好,依旧是在翻看旧文档的时候,发现一篇关于Monkey的介绍和使用,Monkey这款工具在软件测试中主要用于进行压力测试和稳定性测试。它可以模拟大量随机的用户操作&#xf…

Android Studio gradle 默认sourceSets配置

一. AS默认的sourceSets配置 sourceSets在Android插件中如何使用的:android {sourceSets {main {manifest.srcFile AndroidManifest.xmljava.srcDirs [src]resources.srcDirs [src]aidl.srcDirs [src]renderscript.srcDirs [src]res.srcDirs [res]assets.srcD…

数据库服务类--Redis--未授权访问终端Getshell

免责声明:本文仅做技术交流与学习. 目录 前提条件: windows上开启redis服务: Linux上创建&开启redis服务: 操作: 1-连接靶机redis 2-写入webshell 3-访问后门 redis--->webshell Redis未授权访问漏洞复现与利用 - 知乎 (zhihu.com) 前提条件: 端口开放(6379) 目录…

Blender笔记之基本操作

code review! —— 2024-04-27 杭州 Blender笔记…

JavaEE——介绍 HTTPServlet 三部分使用与 cookie 和 session 的阐述

文章目录 一、HTTPServlet介绍其中的关键 三个方法 二、HTTPServletRequest(处理请求)1.分块介绍方法作用get 为前缀的方法字段中 含有 getParameter 字段 的方法(前后端交互):字段中 含有 getHeader 字段 的方法: 2.解释前后端的交互过程3.使用 json 格…

保护企业财务报告,这款防泄密软件做得到!

在日益增长的金融欺诈和网络攻击中,保护企业的财务报告是维持公司声誉和稳定运营的关键。财务报告包含了公司的敏感信息,如利润、收入、财务结构等,一旦泄露,可能会对公司造成不利影响。华企盾DSC数据防泄密系统为企业提供了全面的解决方案,确保财务报告的安全性和机密性。…

保护企业财务报告,这几款防泄密软件做得到!

在日益增长的金融欺诈和网络攻击中,保护企业的财务报告是维持公司声誉和稳定运营的关键。财务报告包含了公司的敏感信息,如利润、收入、财务结构等,一旦泄露,可能会对公司造成不利影响。华企盾DSC数据防泄密系统为企业提供了全面的解决方案,确保财务报告的安全性和机密性。…

OSPF路由计算

1.区域内路由计算 (1)LSA的基本概念 LS Age:当LSA被始发时,该字段为0,随着LSA在网络中被泛洪,该时间逐渐累加,当到达MaxAge(缺省值为3600s)时,LSA不再用于路…

LeetCode 面试题 17.08 —— 马戏团人塔

阅读目录 1. 题目2. 解题思路3. 代码实现 1. 题目 2. 解题思路 首先,我们对人的身高按照从小到大排序,特别注意,对于身高相等的人,要按照体重从高到低排序。这时候,序列已经满足了在上面的人要比下面的人矮一点&#…

K8S上生产环境后,90%都会遇到这个故障

K8S上生产环境后,90%都会遇到这个故障 原创 didiplus 攻城狮成长日记 2024-03-26 21:30 广东 听全文在Kubernetes/K8s上生产环境中,90%的人都会遇到的一个故障,K8s集群突然有一天执行kubectl命令时,报错提示509证书过期。返回如下报错信息: Unable to connect to the serve…

Bayes判别示例数据:鸢尾花数据集

使用Bayes判别的R语言实例通常涉及使用朴素贝叶斯分类器。朴素贝叶斯分类器是一种简单的概率分类器,基于贝叶斯定理和特征之间的独立性假设。在R中,我们可以使用e1071包中的naiveBayes函数来实现这一算法。下面,我将通过一个简单的示例展示如…