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语句。 

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

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

相关文章

MySQL中的事务, 特性及应用

事务 1 &#xff09;概述 只有 innodb 引擎支持事务&#xff0c;myisam 是不支持的事务的本质是原子性操作&#xff0c;不可分割&#xff0c;打包多个操作成为一个原子 2 &#xff09;事务的四大特性(ACID) 原子性 Atomicity 原子性是指事务包含的所有操作不可分割要成功一…

ElasticSearch使用Grafana监控服务状态-Docker版

文章目录 版本信息构建docker-compose.yml参数说明 创建Prometheus配置文件启动验证配置Grafana导入监控模板模板说明 参考资料 版本信息 ElasticSearch&#xff1a;7.14.2 elasticsearch_exporter&#xff1a;1.7.0&#xff08;latest&#xff09; 下载地址&#xff1a;http…

C++ 基础知识体系

一&#xff0c;C基础知识体系 基于自己的编程经验搭建的C知识体系 宏声明与定义函数 函数重载函数指针内敛函数默认参数函数对象 面向对象 面向对象与面向过程的区别封装 数据成员成员方法静态成员 继承 单继承多继承虚继承菱形继承 多态 虚函数纯虚函数抽象类 五大原则 单一职…

如何使用 Python+selenium 进行 web 自动化测试?

Selenium是一个自动化测试工具&#xff0c;它可以模拟用户在浏览器中的操作&#xff0c;比如点击、输入、选择等等。它支持多种浏览器&#xff0c;包括Chrome、Firefox、Safari等等&#xff0c;并且可以在多个平台上运行。 安装和配置Selenium 在使用Selenium之前&#xff0c;…

【VTK三维重建-体绘制】第五期 vtkLODProp3D

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ&#xff1a;870202403 前言 本文分享VTK中体绘制中的vtkLODProp3D对象&#xff0c;希望对各位小伙伴有所帮助&#xff01; 感谢各位小伙伴的点赞关注&#xff0c;小易会继续努力分享&#xff0c;一起进步&#xff01; 你的点赞…

机器学习中异常值的处理方式

背景 3Sigma、Z-Score、box plot、Grubbs假设检验四种分布异常值检验方法可以帮助在数据中识别异常值&#xff0c;而在机器学习中&#xff0c;异常值的检测对模型性能和结果的准确性具有重要影响。 3 Sigma法&#xff1a; 原理&#xff1a;通过计算数据的均值和标准差&#xff…

力扣labuladong——一刷day84

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、力扣743. 网络延迟时间 前言 Dijkstra 算法&#xff08;一般音译成迪杰斯特拉算法&#xff09;无非就是一个 BFS 算法的加强版&#xff0c;它们都是从二叉…

(Java企业 / 公司项目)Nacos的怎么搭建多环境配置?(含相关面试题)(二)

上一篇讲了一个单体服务中配置&#xff0c;传统的Nacos配置但是在微服务架构当中肯定都是多环境下配置&#xff0c;比如生产环境&#xff0c;dev测试环境等等。 第一种方式模拟开始&#xff1a; 首先展示在生产环境中nacos如何配置&#xff0c;在模块下新建一个配置文件&…

达梦数据库安装超详细教程(小白篇)

文章目录 达梦数据库一、达梦数据库简介二、达梦数据库下载三、达梦数据库安装1. 解压2. 安装 四、初始化数据库五、DM管理工具 达梦数据库 一、达梦数据库简介 ​ 达梦数据库管理系统是达梦公司推出的具有完全自主知识产权的高性能数据库管理系统&#xff0c;简称DM。 达梦数…

本地站点通过主备冗余专线连接上云

本地站点通过主备冗余专线连接上云 您可以使用两条物理专线以主备方式将本地数据中心IDC&#xff08;Internet Data Center&#xff09;接入阿里云。采用主备接入方式时&#xff0c;正常情况下仅主用线路在进行流量转发。阿里云按照您配置的健康检查的发包时间间隔探测主用线路…

【Midjourney】AI绘画新手教程(一)登录和创建服务器,生成第一幅画作

一、登录Discord 1、访问Discord官网 使用柯學尚网&#xff08;亲测非必须&#xff0c;可加快响应速度&#xff09;访问Discord官方网址&#xff1a;https://discord.com 选择“在您的浏览器中打开Discord” 然后&#xff0c;注册帐号、购买套餐等&#xff0c;在此不做缀述。…

uniapp+echarts开发APP版本教程

需求 需要在uniappecharts展示图表功能&#xff0c;是APP版本&#xff0c;不是小程序。找了好多教程都乱七八糟的&#xff0c;无法实现。以下是效果图 教程 1、安装插件 HBuilder安装echarts插件&#xff0c;插件地址如下。安装完成后在uni_modules/lime-echart文件夹下 ht…

12.2 【Screen配置】khronos模块配置

一,khronos配置配置简介 khronos部分的配置用于指定与Khronos相关的库和参数(例如EGL和WFD库)。 在graphics.conf配置文件中,khronos部分指定GPU和显示驱动程序。只有在系统需要这两种类型的驱动程序之一或两者时,才需要在配置文件中包含此部分。khronos部分由begin khr…

使用169.254开头的IP地址

介绍&#xff1a; 在计算机网络中&#xff0c;当设备无法通过DHCP服务器获取有效的IP地址时&#xff0c;它会尝试使用自动私有IP地址&#xff08;APIPA&#xff09;来分配一个本地链接的IP地址。APIPA地址范围从169.254.0.1到169.254.255.254。这篇文档将介绍关于使用以169.254…

主板部件

▶1.主要部件 主板是计算机的重要部件&#xff0c;主板由集成电路芯片、电子元器件、电路系统、各种总线插座和接口组成&#xff0c;目前主板标准为ATX。主板的主要功能是传输各种电子信号&#xff0c;部分芯片负责初步处理一些外围数据。不同类型的CPU,需要不同主板与之匹配。…

微信小程序+前后端开发学习材料

目录结构 全局文件 1.app.json 文件 用来对微信小程序进行全局配置&#xff0c;决定页面文件的路径、窗口表现、设置网络超时时间、设置多 tab 等。文件内容为一个 JSON 对象。 1.1 page用于指定小程序由哪些页面组成&#xff0c;每一项都对应一个页面的 路径&#xff08;含文…

docker镜像仓库详解(Docker Registry)

本片文章主要是对docker的镜像仓库进行了详解。其中包含了一些常用了 docker 指令&#xff0c;通过举例进行详解。也详细解释了镜像仓库的工作机制和常见的镜像仓库。也实际拉去和运行了一些镜像。希望本篇文章会对你有所帮助&#xff01; 文章目录 一、什么是Docker Registry …

【卡梅德生物】杂交瘤技术、噬菌体展示技术和兔单B细胞技术制备兔单抗的对比

兔单克隆抗体技术的演进经历了杂交瘤技术、噬菌体展示技术和单B细胞技术三个关键阶段。这些技术的不断进步推动了兔单克隆抗体技术的优化&#xff0c;显著提高了抗体的生产效率、特异性和适用范围。在科研和医药领域&#xff0c;兔单克隆抗体技术因其不断发展的特性而取得了令人…

Java IO流(三)-字节流缓冲流

1字节缓冲区流 1.1 字节缓冲流概述 字节缓冲流&#xff1a; ​ BufferOutputStream&#xff1a;缓冲输出流​ BufferedInputStream&#xff1a;缓冲输入流 构造方法&#xff1a; ​ 字节缓冲输出流&#xff1a;BufferedOutputStream(OutputStream out)​ 字节缓冲输入流&…

Nginx 中 return 和 rewrite 跳转

目录 1.return 跳转 2.rewrite 跳转 如果把https的s去掉&#xff0c;就相当于去访问80端口了&#xff0c;https默认找的是443端口&#xff0c;而80端 口对应的网站我们设置了默认网站&#xff0c;所以如果你删掉了s再访问&#xff0c;就看到我们的默认网站了 我们想要的效果…