当前位置: 首页 > news >正文

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中,match4个分支。 

        每个分支所关联的代码同时也是一个表达式,而这个表达式运行所得到的结果值,同时也会被作为整个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,并返回一个新的包含了结果为6Some值。

        现在,再让我们来看一看示例6-5plus_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可以合法地存储从0255之间的所有整数。但假设我们只关心值为1357时的情形,我们就没有必要去列出024689直到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中有一个异常强大的控制流运算符&#xff1a;match&#xff0c;它允许将一个值与一系列的模式相比较&#xff0c;并根据匹配的模式执行相应代码。模式可由字面量、变量名、通配符和许多其他东西组成&#xff1b;后文会详细介绍所有不同种类的模式及它…...

个人博客主题 vuepress-hope

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

【LeetCode-剑指offer】--19.验证回文串II

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

锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于LSTM长短期记忆神经网络的锂电池寿命预测 程序设计 完整程序和数据获取方式&#xff1a;私信博主回复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。 从九月份开学到现在&#xff0c;已经学了Linux&#xff0c;数据结构&#xff0c;SLAM&#xff0c;C的基础操作&#xff0c;期间还参与编写了一本VHDL的教材。还有上课、考试什么的其他杂七杂八的事情就不说了。 读研好苦逼&…...

不能错过的AI前沿开源工具!

&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308;&#x1f308; 欢迎关注公众号&#xff08;通过文章导读关注&#xff1a;【11来了】&#xff09;&#xff0c;及时收到 AI 前沿项目工具及新技术 的推送 发送 资料 可领取 深入理…...

为什么深度学习神经网络可以学习任何东西

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

使用 SpringSecurity 发送POST请求出现 403

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

解决Typora笔记上传到CSDN上图片无法显示的问题

解决Typora笔记上传到CSDN上图片无法显示的问题 一、发现问题二、分析问题三、解决问题图床介绍所需工具PicGo软件安装操作下载安装PicGo配置PicGo 设置Typora 四、总结 一、发现问题 当我们使用Typora这款强大的Markdown编辑器记录笔记时&#xff0c;经常会遇到一个让人困扰的…...

Vue3.0+Echarts (可视化界面)

Vue3.0Echarts &#xff08;可视化界面&#xff09; 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…...

编程语言的未来:探索技术进步的轨迹

编程语言的未来&#xff1a;探索技术进步的轨迹 随着科技的飞速发展&#xff0c;编程语言在计算机领域中扮演着至关重要的角色。它们是软件开发的核心&#xff0c;为程序员提供了与机器沟通的桥梁。然而&#xff0c;未来的技术进步将如何影响编程语言的走向呢&#xff1f;让我…...

SOLIDWORKS使用技巧——SOLIDWORKS草图绘制时一定要完全定义

SOLIDWORKS草图的定义状态有多种&#xff0c;按是否报错区分&#xff0c;如下&#xff1a; 1. 正常状态&#xff1a;欠定义、完全定义&#xff1b; 2. 错误状态的&#xff1a;过定义、悬空、无解&#xff1b; 其中&#xff0c;错误状态需要修复&#xff0c;不然会影响模型重…...

网络类型之GRE和MGRE和NHRP

GRE-通用路由封装 是一种简单的三层VPN封装技术&#xff0c;属于虚拟的点到点网络类型 优点&#xff1a;支持IP 网络作为承载网络、支持多种协议、支持IP 组播&#xff0c;配置简单&#xff0c;容易布署。 缺点&#xff1a;缺少保护功能&#xff0c;不能执行如认证、加密、以…...

uniapp获取日期

1.使用new Date()方法获取系统今天的日期&#xff0c;显示格式为&#xff1a;2023-10-28 <template><view class"content">{{date}}</view> </template> <script>export default {data() {return {date: new Date().toISOString().sl…...

编码和解码的未来之路

hello&#xff0c;我是小索奇。在计算机科学的世界中&#xff0c;编码和解码是无处不在的神奇力量&#xff0c;而现代技术的巅峰之一就是 ChatGPT。让我们一起探讨编码和解码如何与 ChatGPT 这一人工智能的杰作相互结合&#xff0c;打开了无限可能的数字世界之门。 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

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

【单片机项目实战】温度控制系统

本项目的主要作用是实现温度调控&#xff0c;通过设定一个预定的温度值&#xff0c;实现实时检测外界温度&#xff0c;当外界温度小于预定值时&#xff0c;电机正转&#xff0c;实现降温效果&#xff1b;当外界温度大于预定值时&#xff0c;电机反转&#xff0c;实现升温效果&a…...

SpringMVC-视图

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

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

Auto-Coder使用GPT-4o完成:在用TabPFN这个模型构建一个预测未来3天涨跌的分类任务

通过akshare库&#xff0c;获取股票数据&#xff0c;并生成TabPFN这个模型 可以识别、处理的格式&#xff0c;写一个完整的预处理示例&#xff0c;并构建一个预测未来 3 天股价涨跌的分类任务 用TabPFN这个模型构建一个预测未来 3 天股价涨跌的分类任务&#xff0c;进行预测并输…...

【2025年】解决Burpsuite抓不到https包的问题

环境&#xff1a;windows11 burpsuite:2025.5 在抓取https网站时&#xff0c;burpsuite抓取不到https数据包&#xff0c;只显示&#xff1a; 解决该问题只需如下三个步骤&#xff1a; 1、浏览器中访问 http://burp 2、下载 CA certificate 证书 3、在设置--隐私与安全--…...

Springcloud:Eureka 高可用集群搭建实战(服务注册与发现的底层原理与避坑指南)

引言&#xff1a;为什么 Eureka 依然是存量系统的核心&#xff1f; 尽管 Nacos 等新注册中心崛起&#xff0c;但金融、电力等保守行业仍有大量系统运行在 Eureka 上。理解其高可用设计与自我保护机制&#xff0c;是保障分布式系统稳定的必修课。本文将手把手带你搭建生产级 Eur…...

Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理

引言 Bitmap&#xff08;位图&#xff09;是Android应用内存占用的“头号杀手”。一张1080P&#xff08;1920x1080&#xff09;的图片以ARGB_8888格式加载时&#xff0c;内存占用高达8MB&#xff08;192010804字节&#xff09;。据统计&#xff0c;超过60%的应用OOM崩溃与Bitm…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

Python ROS2【机器人中间件框架】 简介

销量过万TEEIS德国护膝夏天用薄款 优惠券冠生园 百花蜂蜜428g 挤压瓶纯蜂蜜巨奇严选 鞋子除臭剂360ml 多芬身体磨砂膏280g健70%-75%酒精消毒棉片湿巾1418cm 80片/袋3袋大包清洁食品用消毒 优惠券AIMORNY52朵红玫瑰永生香皂花同城配送非鲜花七夕情人节生日礼物送女友 热卖妙洁棉…...

C++使用 new 来创建动态数组

问题&#xff1a; 不能使用变量定义数组大小 原因&#xff1a; 这是因为数组在内存中是连续存储的&#xff0c;编译器需要在编译阶段就确定数组的大小&#xff0c;以便正确地分配内存空间。如果允许使用变量来定义数组的大小&#xff0c;那么编译器就无法在编译时确定数组的大…...