015、控制流运算符match
1. 控制流运算符match
Rust中有一个异常强大的控制流运算符:match,它允许将一个值与一系列的模式相比较,并根据匹配的模式执行相应代码。模式可由字面量、变量名、通配符和许多其他东西组成;后文会详细介绍所有不同种类的模式及它们的工作机制。
match的能力不仅来自模式丰富的表达力,也来自编译器的安全检查,它确保了所有可能的情况都会得到处理。你可以将match表达式想象成一台硬币分类机:硬币滑入有着不同大小孔洞的轨道,并且掉入第一个符合大小的孔洞。
同样,值也会依次通过match中的模式,并且在遇到第一个“符合”的模式时进入相关联的代码块,并在执行过程中被代码所使用。
由于我们正好提到了硬币,所以就用它们来编写一个使用match的示例!示例中的函数会接收一个美国的硬币作为输入,并以一种类似于验钞机的方式,确定硬币的类型并返回它的分值,如示例6-3所示。
// 示例6-3:一个枚举以及一个以枚举变体作为模式的match表达式❶enum Coin {Penny,Nickel,Dime,Quarter,
}fn value_in_cents(coin: Coin) -> u32 {❷ match coin {❸ Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}
}
让我们先来逐步分析一下函数value_in_cents中的match块。首先,我们使用的match关键字后面会跟随一个表达式,也就是本例中的coin值❷。
初看上去,这与if表达式的使用十分相似,但这里有个巨大的区别:在if语句中,表达式需要返回一个布尔值,而这里的表达式则可以返回任何类型。
例子中coin的类型正是我们在首行❶中定义的Coin枚举。接下来是match的分支,一个分支由模式和它所关联的代码组成。第一个分支采用了值Coin::Penny作为模式,并紧跟着一个=>运算符用于将模式和代码区分开来❸。
这里的代码简单地返回了值1。不同分支之间使用了逗号分隔。当这个match表达式执行时,它会将产生的结果值依次与每个分支中的模式相比较。
假如模式匹配成功,则与该模式相关联的代码就会被继续执行。而假如模式匹配失败,则会继续执行下一个分支,就像上面提到过的硬币分类机一样。分支可以有任意多个,在示例6-3中,match有4个分支。
每个分支所关联的代码同时也是一个表达式,而这个表达式运行所得到的结果值,同时也会被作为整个match表达式的结果返回。
如果分支代码足够短,就像示例6-3中仅返回一个值的话,那么通常不需要使用花括号。但是,假如我们想要在一个匹配分支中包含多行代码,那么就可以使用花括号将它们包裹起来。
例如,下面的代码会在每次给函数传入Coin::Penny时打印“Lucky penny!”,同时仍然返回代码块中最后的值1:
fn value_in_cents(coin: Coin) -> u32 {match coin {Coin::Penny => {println!("Lucky penny!");1},Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}
}
2. 绑定值的模式
匹配分支另外一个有趣的地方在于它们可以绑定被匹配对象的部分值,而这也正是我们用于从枚举变体中提取值的方法。
下面举一个例子,让我们修改上面的枚举变体来存放数据。在1999年到2008年之间,美国在25美分硬币的一侧为50个州采用了不同的设计。其他类型的硬币都没有类似的各州的设计,所以只有25美分拥有这个特点。
我们可以通过在Quarter变体中添加一个UsState值,来将这些信息添加至枚举中,如示例6-4所示。
// 示例6-4:Coin枚举中的Quarter变体存放了一个UsState值#[derive(Debug)] // 使我们能够打印并观察各州的设计
enum UsState {Alabama,Alaska,// --略--
}enum Coin {Penny,Nickel,Dime,Quarter(UsState),
}
假设我们有一个朋友正在尝试收集所有50个州的25美分硬币。当我们在根据硬币类型进行大致分类的时候,也可以打印出每个25美分硬币所对应的州的名字。
一旦这个朋友发现了没有的硬币,就可以将其加入自己的收藏中。在这份代码的匹配表达式中,我们在模式中加入了一个叫作state的变量用于匹配变体Coin::Quarter中的值。
当匹配到Coin::Quarter时,变量state就会被绑定到25美分所包含的值上。接着,我们就可以在这个分支中像下面一样使用state了:
fn value_in_cents(coin: Coin) -> u32 {match coin {Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter(state) => {println!("State quarter from {:?}!", state);25},}
}
如果我们在代码中调用value_in_cents(Coin::Quarter(UsState:: Alaska)),Coin::Quarter(UsState::Alaska)就会作为coin的值传入函数。
这个值会依次与每个分支进行匹配,一直到Coin:: Quarter(state)模式才会终止匹配。这时,值UsState::Alaska就会被绑定到变量state上。
接着,我们就可以在println! 表达式中使用这个绑定了,这就是从Coin枚举的变体Quarter中获取值的方法。
3. 匹配Option<T>
在上篇文章中,我们曾经想要在使用Option<T>时,从Some中取出内部的T值;现在我们就可以如同操作Coin枚举一样,使用match来处理Option<T>了!
除了使用Option<T>的变体而不是Coin的变体来进行比较,match表达式的大部分工作流程完全一致。
比如,我们想要编写一个接收Option<i32>的函数,如果其中有值存在,则将这个值加1。如果其中不存在值,那么这个函数就直接返回None而不进行任何操作。
得益于match方法的使用,编写这个函数将会非常简单,它看起来会如示例6-5所示:
// 示例6-5:一个对Option<i32>使用match表达式的函数fn plus_one(x: Option<i32>) -> Option<i32> {match x {❶ None => None,❷ Some(i) => Some(i + 1),}
}let five = Some(5);
let six = plus_one(five);❸
let none = plus_one(None);❹
让我们来分析一下首次执行plus_one的过程中究竟发生了些什么。当我们调用plus_one(five)❸时,plus_one函数体中的变量x被绑定为值Some(5)。随后我们会将这个值与各个分支进行比较。
自然,Some(5)没办法匹配上模式None❶,所以我们继续尝试与下一个分支进行比较。❷这里Some(5)会匹配上Some(i)吗?答案是肯定的!匹配的两端拥有相同的变体。
这里的i绑定了Some所包含的值,也就是5。接着,这个匹配分支中的代码得到执行,我们将i中的值加1,并返回一个新的包含了结果为6的Some值。
现在,再让我们来看一看示例6-5中plus_one的第二次调用,这一次,x变成了None❹。依然继续进入match表达式,并将它与第一个分支❶进行比较。
它们匹配上了!这里我们没有可用于增加的对象,所以=>右侧的程序会简单地终止并返回None值。由于第一个分支匹配成功,因此其他的分支会被跳过。
将match与枚举相结合在许多情形下都是非常有用的。你会在Rust代码中看到许多类似的套路:使用match来匹配枚举值,并将其中的值绑定到某个变量上,接着根据这个值执行相应的代码。
这初看起来可能会有些复杂,不过一旦你习惯了它的用法,就会希望在所有的语言中都有这个特性。这一特性一直以来都是社区用户的最爱。
4. 匹配必须穷举所有的可能
match表达式中还有另外一个需要注意的特性。你可以先来看下面这个存在bug、无法编译的plus_one函数版本:
fn plus_one(x: Option<i32>) -> Option<i32> {match x {Some(i) => Some(i + 1),}
}
此段代码的问题在于我们忘记了处理值是None的情形。幸运的是,这是一个Rust可以轻松捕获的问题。假如我们尝试去编译这段代码,就会看到如下所示的错误提示信息:
error[E0004]: non-exhaustive patterns: `None` not covered-->|
6 | match x {| ^ pattern `None` not covered
Rust知道我们没有覆盖所有可能的情形,甚至能够确切地指出究竟是哪些模式被我们漏掉了!
Rust中的匹配是穷尽的(exhausitive):我们必须穷尽所有的可能性,来确保代码是合法有效的。
特别是在这个Option<T>的例子中,Rust会强迫我们明确地处理值为None的情形。这使得我们不需要去怀疑所持有值的存在性,因而可以有效地避免前面提到过的10亿美金的错误。
5. _通配符
有的时候,我们可能并不想要处理所有可能的值,Rust同样也提供了一种模式用于处理这种需求。
例如,一个u8可以合法地存储从0到255之间的所有整数。但假设我们只关心值为1、3、5或7时的情形,我们就没有必要去列出0、2、4、6、8、9直到255等其余的值。
所幸我们也确实可以避免这种情形,即通过使用一个特殊的模式_来替代其余的值:
let some_u8_value = 0u8;
match some_u8_value {1 => println!("one"),3 => println!("three"),5 => println!("five"),7 => println!("seven"),_ => (),
}
这里的_模式可以匹配任何值。通过将它放置于其他分支后,可以使其帮我们匹配所有没有被显式指定出来的可能的情形。
与它对应的代码块里只有一个()空元组,所以在_匹配下什么都不会发生。使用它也就暗示了,我们并不关心那些在_通配符前没有显式列出的情形,且不想为这些情形执行任何操作。
不过,在只关心某一种特定可能的情形下,使用match仍然会显得有些烦琐。为此,Rust提供了if let语句。
相关文章:
015、控制流运算符match
1. 控制流运算符match Rust中有一个异常强大的控制流运算符:match,它允许将一个值与一系列的模式相比较,并根据匹配的模式执行相应代码。模式可由字面量、变量名、通配符和许多其他东西组成;后文会详细介绍所有不同种类的模式及它…...

个人博客主题 vuepress-hope
文章目录 1. 简介2. 配置2.1 个人博客,社媒链接配置 非常推荐vuepress-hope 1. 简介 下面的我的博客文章的截图 通过md写博客并且可以同步到github-page上 2. 配置 2.1 个人博客,社媒链接配置 配置文件 .vuepress/theme.ts blog: {medias: {BiliB…...

【LeetCode-剑指offer】--19.验证回文串II
19.验证回文串II 方法:双指针 首先考虑如果不允许删除字符,如何判断一个字符串是否是回文串。常见的做法是使用双指针。定义左右指针,初始时分别指向字符串的第一个字符和最后一个字符,每次判断左右指针指向的字符是否相同&#…...

锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测
目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测 程序设计 完整程序和数据获取方式:私信博主回复Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测。 参考资料 [1] http://t.csdn…...

JSON 详解
文章目录 JSON 的由来JSON 的基本语法JSON 的序列化简单使用stringify 方法之 replacerstringify 方法之 replacer 参数传入回调函数stringify 方法之 spacestringify 方法之 toJSONparse 方法之 reviver 利用 stringify 和 parse 实现深拷贝 json 相信大家一定耳熟能详&#x…...

我不想学JAVA---------JAVA和C的区别
前言 我一个研究方向是SLAM的为什么要来学JAVA。 从九月份开学到现在,已经学了Linux,数据结构,SLAM,C的基础操作,期间还参与编写了一本VHDL的教材。还有上课、考试什么的其他杂七杂八的事情就不说了。 读研好苦逼&…...

不能错过的AI前沿开源工具!
🌈🌈🌈🌈🌈🌈🌈🌈 欢迎关注公众号(通过文章导读关注:【11来了】),及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…...

为什么深度学习神经网络可以学习任何东西
下图你所看到的,是著名的曼德尔布罗特集,我们可以见证这个集合呈现出的复杂形态: 要理解神经网络如何学习曼德尔布罗特集,我们首先需要从最基础的数学概念讲起:什么是函数?函数本质上是一个将输入转化为输出…...

使用 SpringSecurity 发送POST请求出现 403
问题场景 在使用 SpringSecurity 时对一些访问权限进行了设置, 在用户请求资源时出现了403错误 , 通过检查代码发现请求权限是开放的, 并且切换成 GET 请求也是可以通过, 换成POST 请求就无法通过。 解决方法 在 SpringSecurity 中关闭 CSRF 因为 前端向后台发送 post 请求…...

解决Typora笔记上传到CSDN上图片无法显示的问题
解决Typora笔记上传到CSDN上图片无法显示的问题 一、发现问题二、分析问题三、解决问题图床介绍所需工具PicGo软件安装操作下载安装PicGo配置PicGo 设置Typora 四、总结 一、发现问题 当我们使用Typora这款强大的Markdown编辑器记录笔记时,经常会遇到一个让人困扰的…...
Vue3.0+Echarts (可视化界面)
Vue3.0Echarts (可视化界面) 1. 简介2. 安装2.1 下载安装Node.js2.2 全局下载项目脚手架2.3 创建项目 1. 简介 2. 安装 2.1 下载安装Node.js 2.2 全局下载项目脚手架 以管理员身份执行 npm install -g vue/cli vue --version2.3 创建项目 vue crea…...
编程语言的未来:探索技术进步的轨迹
编程语言的未来:探索技术进步的轨迹 随着科技的飞速发展,编程语言在计算机领域中扮演着至关重要的角色。它们是软件开发的核心,为程序员提供了与机器沟通的桥梁。然而,未来的技术进步将如何影响编程语言的走向呢?让我…...

SOLIDWORKS使用技巧——SOLIDWORKS草图绘制时一定要完全定义
SOLIDWORKS草图的定义状态有多种,按是否报错区分,如下: 1. 正常状态:欠定义、完全定义; 2. 错误状态的:过定义、悬空、无解; 其中,错误状态需要修复,不然会影响模型重…...

网络类型之GRE和MGRE和NHRP
GRE-通用路由封装 是一种简单的三层VPN封装技术,属于虚拟的点到点网络类型 优点:支持IP 网络作为承载网络、支持多种协议、支持IP 组播,配置简单,容易布署。 缺点:缺少保护功能,不能执行如认证、加密、以…...
uniapp获取日期
1.使用new Date()方法获取系统今天的日期,显示格式为:2023-10-28 <template><view class"content">{{date}}</view> </template> <script>export default {data() {return {date: new Date().toISOString().sl…...
编码和解码的未来之路
hello,我是小索奇。在计算机科学的世界中,编码和解码是无处不在的神奇力量,而现代技术的巅峰之一就是 ChatGPT。让我们一起探讨编码和解码如何与 ChatGPT 这一人工智能的杰作相互结合,打开了无限可能的数字世界之门。 ChatGPT的魔…...

Prometheus实战篇:Prometheus监控redis
准备环境 docker-compose安装redis docker-compose.yaml version: 3 services:redis:image:redis:5container_name: rediscommand: redis-server --requirepass 123456 --maxmemory 512mbrestart: alwaysvolumes:- /data/redis/data: /dataport:- "6379:6379"dock…...

Vue2.Hello World
步骤: 准备容器引包(开发版本/生产版本)创建实例new Vue()添加配置项 el指定挂载点data提供数据 准备容器 就是新建一个div标签 引包 vue2版本中文文档:https://v2.cn.vuejs.org/v2/guide/ 尝试 Vue.js 最简单的方法是使用 …...

【单片机项目实战】温度控制系统
本项目的主要作用是实现温度调控,通过设定一个预定的温度值,实现实时检测外界温度,当外界温度小于预定值时,电机正转,实现降温效果;当外界温度大于预定值时,电机反转,实现升温效果&a…...

SpringMVC-视图
SpringMVC中的视图实现了View接口,作用是渲染数据,将Model中的数据展示给用户。render是渲染方法,可以看到渲染的视图是一个View类型的对象。 SpringMVC视图的种类有很多,默认有转发视图和重定向视图。 如果配置了Thymeleaf视图解…...

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)
题目:3442. 奇偶频次间的最大差值 I 思路 :哈希,时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况,哈希表这里用数组即可实现。 C版本: class Solution { public:int maxDifference(string s) {int a[26]…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...

MMaDA: Multimodal Large Diffusion Language Models
CODE : https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA,它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

selenium学习实战【Python爬虫】
selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

搭建DNS域名解析服务器(正向解析资源文件)
正向解析资源文件 1)准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2)服务端安装软件:bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

计算机基础知识解析:从应用到架构的全面拆解
目录 前言 1、 计算机的应用领域:无处不在的数字助手 2、 计算机的进化史:从算盘到量子计算 3、计算机的分类:不止 “台式机和笔记本” 4、计算机的组件:硬件与软件的协同 4.1 硬件:五大核心部件 4.2 软件&#…...