Rust中的枚举和模式匹配
专栏简介:本专栏作为Rust语言的入门级的文章,目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言,虽然历史没有C++、和python历史悠远,但是它的优点可以说是非常的多,既继承了C++运行速度,还拥有了Java的内存管理,就我个人来说,还有一个优点就是集成化的编译工具cargo,语句风格和C++极其相似,所以说我本人还是比较喜欢这个语言,特此建立这个专栏,作为学习的记录分享。
日常分享:每天努力一点,不为别的,只是为了日后,能够多一些选择,选择舒心的日子,选择自己喜欢的人!
前面我们提到过,Rust中没有了switch case这种模式控制语句,但是喃,除此之外,却又多了另一种匹配规则,那就是模式匹配。所以这节我们就来聊聊模式匹配这种匹配机制。
1、枚举
枚举其实在c++中就有过定义,二者相差不大,关键字是enum,枚举和结构体一样,也是用来自定义的数据类型。
说到枚举,可能有些同学还不是特别清楚,枚举的意义在那里,其实枚举他只是一个存放字段的一种容器吧,在后面的代码中,如果你需要多种字段,但是你又不是特别明确具体需要哪些,就把所有可能的字段放在其中,需要什么就使用什么。
enum Error{typeError,lengthError,
}
例如上面的代码,定义了一个Error的枚举类型,这个时候,Error就是一个数据类型。
1.1、枚举值
let oneError = Error::typeError;let twoEroor = Error::lengthError;
就如上面的代码,我们定义了两个实例对象,而他们的数值则是Error中的两个字段。
这里注意的是,枚举的成员位于其标识符的命名空间中,并使用两个冒号分开。
但是有人看到这里就会有疑惑,这里的枚举类型中的字段都是没有具体值的,那么我们如何将值与枚举成员关联?
上一节讲解了结构体的概念,这里我们就可以使用结构体来进行绑定:
enum Error{typeError,lengthError,
}struct getError{oneError: Error,twoEroorderError: Error,address:String,
}
let amples = getError{oneError: Error::typeError,twoEroorderError: Error::lengthError,address:String::from("Hello world"),
};
上面所时代码就是将枚举作为结构体的一部分,除了上面的方法,我们似乎还可以使用其他方法,例如将数据放进每一个枚举成员。
enum Error{typeError(String),lengthError(String),
}
let oneError = Error::typeError(String::from("one error"));
let twoEroor = Error::lengthError(String::from("two Eroor error"));
1.2、Option枚举
前面写的代码中,对于枚举数据类型,虽然将值通过结构体进行了绑定,但是却没有具体的值,只有通过将值放进枚举成员,才能获得值。那么没有的值又是什么?或者说又有什么作用?
Rust语言和其他语言的一点不同就在于它没有空值,也就是说不能赋予空值,必须去实现。Rust 并没有空值,不过它确实拥有一个可以编码存在或不存在概念的枚举。
enum Option<T>{
None,
Some(T),
}
Option<T>
枚举是如此有用以至于它甚至被包含在了 prelude 之中,你不需要将其显式引入作用域。另外,它的成员也是如此,可以不需要 Option::
前缀来直接使用 Some
和 None
。这里要注意,Option枚举是含在标准库的,不需要我们定义,直接使用,上面知识给出参考。
<T>
语法是一个我们还未讲到的 Rust 功能。它是一个泛型类型参数,后面遇到了我们再详细介绍。
let some_number = Some(5);let some_char = Some('e');let number:Option<i32>=None;
上面的三条语句,变量some_number的类型是i32,some_char的类型是char,而number的类型是i32,只是是一个空值。 对于Option<T>,这里的T可以是任何数据类型,除了赋空值外,一般来说不需要注明变量的数据类型,除非是特殊需要,Rust可以推断其变量的数据类型。如果是赋空值,就必须注明变量的数据类型,否则会报错。
不过这里需要注意的是,Option<T>标注的数据类型与相同的数据类型变量不能进行运算.
let one_num:Option<i32>=some(20);let s:i32=30;println!("{}",one_num+s);
error[E0425]: cannot find function `some` in this scope
--> src/main.rs:45:27
|
45 | let one_num:Option<i32>=some(20);
| ^^^^ help: a tuple variant with a similar name exists (notice the capitalization): `Some`error[E0369]: cannot add `i32` to `Option<i32>`
--> src/main.rs:47:24
|
47 | println!("{}",one_num+s);
| -------^- i32
| |
| Option<i32>Some errors have detailed explanations: E0369, E0425.
For more information about an error, try `rustc --explain E0369`.
error: could not compile `number` due to 2 previous errors
当运行上述代码的时候就会出现这种报错,这是为什么喃?这是由于当我们使用Option<T> 数据类型的时候就表明该数据可能为空,而我们使用i32(或其他数据类型)的时候,就已经表明改变两不可能为空值,所以才会出现报错,根本原因还是在与其数据类型被系统判定为两种数据类型.
换句话说,在对 Option<T>
进行运算之前必须将其转换为 T
。通常这能帮助我们捕获到空值最常见的问题之一:假设某值不为空但实际上为空的情况。
消除了错误地假设一个非空值的风险,会让你对代码更加有信心。为了拥有一个可能为空的值,你必须要显式的将其放入对应类型的 Option<T>
中。接着,当使用这个值时,必须明确的处理值为空的情况。只要一个值不是 Option<T>
类型,你就 可以 安全的认定它的值不为空。这是 Rust 的一个经过深思熟虑的设计决策,来限制空值的泛滥以增加 Rust 代码的安全性。
那么当有一个 Option<T>
的值时,如何从 Some
成员中取出 T
的值来使用它呢?Option<T>
枚举拥有大量用于各种情况的方法:你可以查看它的文档。熟悉 Option<T>
的方法将对你的 Rust 之旅非常有用。
总的来说,为了使用 Option<T>
值,需要编写处理每个成员的代码。你想要一些代码只当拥有 Some(T)
值时运行,允许这些代码使用其中的 T
。也希望一些代码只在值为 None
时运行,这些代码并没有一个可用的 T
值。match
表达式就是这么一个处理枚举的控制流结构:它会根据枚举的成员运行不同的代码,这些代码可以使用匹配到的值中的数据。
2、match控制流结构
我们前面说了在Rust语言中没有switch这种控制流语句,但是它却推出了match这种强大的控制流运算符。在python语言中,match是正则表达式中的匹配函数,所以这里也可以理解为匹配函数。
先来看个例子:
enum error_message{E0425,E0369,E2345,
}
fn get_error_message(message:error_message)->u32{match message{error_message::E0425 =>{println!("cannot find function `some` in this scope");return 0;}error_message::E0369=>{println!("cannot add `i32` to `Option<i32>");return 1;}error_message::E2345=>{println!("could not compile `number` due to 2 previous errors");return 2;}}
}
fn main(){let mut error=get_error_message(error_message::E2345);println!("{}",error);get_error_message(error_message::E0425);
}
就如上面的代码,先是定义了一个枚举数据类型,然后定义了一个函数,在函数中使用了match控制流。根据不同的参数值,返回不同的值,并打印出结果。
1.1、绑定值模式
匹配分支的另一个有用的功能是可以绑定匹配的模式的部分值。这也就是如何从枚举成员中提取值的。
/*
enum error_message{E0425,E0369,E2345,
}
fn get_error_message(message:error_message)->u32{match message{error_message::E0425 =>{println!("cannot find function `some` in this scope");return 0;}error_message::E0369=>{println!("cannot add `i32` to `Option<i32>");return 1;}error_message::E2345=>{println!("could not compile `number` due to 2 previous errors");return 2;}}
}
fn main(){let mut error=get_error_message(error_message::E2345);println!("{}",error);get_error_message(error_message::E0425);
}
*/
#[derive(Debug)]
enum UsState{Alabama,Alaska,
}
enum Coin{Penny,Nickel,Dime,Quarter(UsState),
}
fn value_cents(coin:Coin) -> usize {match coin{Coin::Penny =>{return 1;}Coin::Nickel =>{return 5;}Coin::Dime =>{return 10;}Coin::Quarter(state)=>{println!("State quarter from {:#?}",state);return 25;}}
}
fn main()
{let b=UsState::Alaska;let c=Coin::Quarter(b);value_cents(c);}
如果调用 value_in_cents(Coin::Quarter(UsState::Alaska))
,coin
将是 Coin::Quarter(UsState::Alaska)
。当将值与每个分支相比较时,没有分支会匹配,直到遇到 Coin::Quarter(state)
。这时,state
绑定的将会是值 UsState::Alaska
。接着就可以在 println!
表达式中使用这个绑定了,像这样就可以获取 Coin
枚举的 Quarter
成员中内部的州的值。
1.2、匹配Option<T>
我们在之前的部分中使用 Option<T>
时,是为了从 Some
中取出其内部的 T
值;我们还可以像处理 Coin
枚举那样使用 match
处理 Option<T>
!只不过这回比较的不再是硬币,而是 Option<T>
的成员,但 match
表达式的工作方式保持不变。
例如:
fn plus_amount(amount:Option<i32>)->Option<i32>
{match amount {None=>{println!("该值为空值");return None;}Some(i)=>{println!("该值不是空值,值为{}",i);return Some(i);}}
}
fn main(){let five=Some(5);let num1=plus_amount(five);plus_amount(None);
}
1.3、通配模式和_占位符
其实除了枚举,match控制流也可以用于其他形式,比如:
let num=30;match num{10=>{println!("10");}11 => println!("11"),other => println!("other"),}
上面的代码中,我们在最后使用了other这个变量,这个变量覆盖了所有其他的可能值,除了我们列出来的可能性,other会包含所有的其他可能性,所以other一定要放在最后,否无法达到目的。
不过在这里因该有人发现了,other会绑定match匹配的值,这个我们将上面的程序更改一下,就能的出这个结论:
fn main(){let five=Some(5);let num1=plus_amount(five);plus_amount(None);let num=30;match num{10=>{println!("10");}11 => println!("11"),other => println!("other的值为:{}",other),}
}
other的值为:30
上面就是输出结果,这说明other绑定到了match匹配的值上,这样做的好处就是可以获得匹配值,将其进行使用,但是如果我们不需要使用那个值,这样做就有点浪费,所以Rust也推出了_占位符,占位符只是表示可以匹配任意值而不能绑定到该值。
fn main(){let five=Some(5);let num1=plus_amount(five);plus_amount(None);let num=30;match num{10=>{println!("10");}11 => println!("11"),_ => println!("other"),}
}
3、if let间接控制流
Rust中的if let控制流说的简单点,就相当于c++中的if else语句,对于一些简单的判别,使用if let控制流语句将会简单很多。例如:
fn main()
{let config=Some(3u8);match config{Some(max)=>println!("{}",max),_=>(),}
}
上面面代码的意思是,匹配config的值,如果值是Some,就将值绑定到max变量上,然后输出,否则就忽略。
除了上面这样的方式,我们还可以使用其他的方式:
fn main()
{let config=Some(3u8);if let Some(max)=config{println!("{}",max);}
}
这样看来是不是就简单的多了,所以说从某种角度来看,if let语句确实简单了很多。
#[derive(Debug)]
enum UsState{Alabama,Alaska,
}
enum Coin{Penny,Nickel,Dime,Quarter(UsState),
}
fn main()
{let mut count=0;let b=UsState::Alaska;let coin=Coin::Quarter(b);//以下两种方式都可以/*match coin{Coin::Quarter(state)=>{println!("State quarter from {:#?}",state);}_=>count+=1,}*/if let Coin::Quarter(state) = coin{println!("State quarter from {:#?}",state);}else{count+=1;}
}
4、总结
现在我们涉及到了如何使用枚举来创建有一系列可列举值的自定义类型。我们也展示了标准库的 Option<T>
类型是如何帮助你利用类型系统来避免出错的。当枚举值包含数据时,你可以根据需要处理多少情况来选择使用 match
或 if let
来获取并使用这些值。
你的 Rust 程序现在能够使用结构体和枚举在自己的作用域内表现其内容了。在你的 API 中使用自定义类型保证了类型安全:编译器会确保你的函数只会得到它期望的类型的值。
下一节我们学习模块系统。
相关文章:
Rust中的枚举和模式匹配
专栏简介:本专栏作为Rust语言的入门级的文章,目的是为了分享关于Rust语言的编程技巧和知识。对于Rust语言,虽然历史没有C、和python历史悠远,但是它的优点可以说是非常的多,既继承了C运行速度,还拥有了Java…...
好物周刊#19:开源指北
https://github.com/cunyu1943/JavaPark https://yuque.com/cunyu1943 村雨遥的好物周刊,记录每周看到的有价值的信息,主要针对计算机领域,每周五发布。 一、项目 1. Vditor 一款浏览器端的 Markdown 编辑器,支持所见即所得、…...
分布式数据库(林子雨慕课课程)
文章目录 4. 分布式数据库HBase4.1 HBase简介4.2 HBase数据模型4.3 HBase的实现原理4.4 HBase运行机制4.5 HBase的应用方案4.6 HBase安装和编程实战 4. 分布式数据库HBase 4.1 HBase简介 HBase是BigTable的开源实现 对于网页搜索主要分为两个阶段 1.建立整个网页索引…...
使用UiPath和AA构建的解决方案 3. CRM 自动化
您是否曾经从一个应用程序中查找数据并更新另一个系统? 在许多情况下,人们在系统之间复制和移动数据。有时,可能会发生“转椅活动”,从而导致人为失误。RPA可以帮助我们自动化这些活动,使其更快,同时还可以消除任何人为错误。 在这个项目中,我们将在客户服务中自动化一…...
【C++设计模式之状态模式:行为型】分析及示例
简介 状态模式(State Pattern)是一种行为型设计模式,它允许对象在内部状态改变时改变其行为,看起来就像是改变了其类。状态模式将对象的状态封装成不同的类,并使得对象在不同状态下有不同的行为。 描述 状态模式通过…...
微信小程序使用路由传参和传对象的方法
近期在做微信小程序开发,在页面跳转时,需要携带参数到下一个页面,尤其是将对象传入页面。为了方便重温,特此记录。 路由传字符串参数 原始页面 传递字符串参数比较简单。路由跳转有两种方式,一种是通过navigator组件…...
中国创可贴市场研究与未来预测报告(2023版)
内容简介: 创可贴由胶布(带)、吸水垫、防粘层等组成,胶布以弹性布、棉布、无纺布或PE、PVC、PU打孔膜、TPU等材料为常见基材,涂以氧化锌和橡胶为主要原料的胶浆或医用压敏胶黏剂或丙烯酸酯胶粘剂制成。 目前中国主要…...
水库安全监测方案(实时数据采集、高速数据传输)
一、引言 水库的安全监测对于防止水灾和保障人民生命财产安全至关重要。为了提高水库安全监测的效率和准确性,本文将介绍一种使用星创易联DTU200和SG800 5g工业路由器部署的水库安全监测方案。 二、方案概述 本方案主要通过使用星创易联DTU200和SG800 5g工业路…...
vue项目 ueditor使用示例
简介 UEditor是由百度Web前端研发部开发的所见即所得富文本web编辑器,具有轻量,功能丰富,易扩展等特点。UEditor支持常见的文本编辑功能,如字体、颜色、大小、加粗、斜体、下划线、删除线等,同时还支持超链接、图片上…...
深度学习笔记之优化算法(四)Nesterov动量方法的简单认识
机器学习笔记之优化算法——Nesterov动量方法的简单认识 引言回顾:梯度下降法与动量法Nesterov动量法Nesterov动量法的算法过程描述总结 引言 上一节对动量法进行了简单认识,本节将介绍 Nesterov \text{Nesterov} Nesterov动量方法。 回顾:…...
比 N 小的最大质数
系列文章目录 进阶的卡莎C++_睡觉觉觉得的博客-CSDN博客数1的个数_睡觉觉觉得的博客-CSDN博客双精度浮点数的输入输出_睡觉觉觉得的博客-CSDN博客足球联赛积分_睡觉觉觉得的博客-CSDN博客大减价(一级)_睡觉觉觉得的博客-CSDN博客小写字母的判断_睡觉觉觉得的博客-CSDN博客纸币(…...
JavaScript 生成随机颜色
代码 function color(color) {return (color "0123456789abcdef"[Math.floor(Math.random() * 6)]) && (color.length 6 ? color : arguments.callee(color)); }使用 // 用法1:全部随机生成 "#" color(""); // #201050…...
Savepoints
语法 SAVEPOINT 名称 RELEASE SAVEPOINT 名称 ROLLBACK TRANSACTION TO SAVEPOINT 名称 Savepoints 与BEGIN和COMMIT类似的创建事务的方法,名称不要求唯一且可以嵌套使用。 可以用在BEGIN…COMMIT定义的事务内部或外部。当在外部时,最外层的savepoin…...
【MySQL】基本查询(二)
文章目录 一. 结果排序二. 筛选分页结果三. Update四. Delete五. 截断表六. 插入查询结果结束语 操作如下表 //创建表结构 mysql> create table exam_result(-> id int unsigned primary key auto_increment,-> name varchar(20) not null comment 同学姓名,-> chi…...
Qt:多语言支持,构建全面应用程序“
Qt:强大API、简化框架、多语言支持,构建全面应用程序" 强大的API:Qt提供了丰富的API,包括250多个C类,基于模板的集合、序列化、文件操作、IO设备、目录管理、日期/时间等功能。还包括正则表达式处理和支持2D/3D…...
性能监控-链路级监控工具
常见的链路监控工具,我们都称之为 APM 开源工具 几个开源的好用的工具,它们分别是 Pinpoint、SkyWalking、Zipkin、CAT 网络上也有人对这几个工具做过测试 比对,得到的结论是每个产品对性能的影响都在 10% 以下,其中 SkyWalking …...
clickonce 程序发布到ftp在使用cnd 加速https 支持下载,会不会报错
ClickOnce 是一种用于发布和部署.NET应用程序的技术,通常用于本地部署或通过网络分发应用程序。将 ClickOnce 程序发布到 FTP 服务器并使用 CDN(内容分发网络)进行加速是可能的,但要确保配置正确以避免出现错误。 在使用 CDN 加速…...
Nginx详细学习记录
1. Nginx概述 Nginx是一个轻量级的高性能HTTP反向代理服务器,同时它也是一个通用类型的代理服务器,支持绝大部分协议,如TCP、UDP、SMTP、HTTPS等。 1.1 Nginx基础架构 Nginx默认采用多进程工作方式,Nginx启动后,会运行…...
golang gin——中间件编程以及jwt认证和跨域配置中间件案例
中间件编程jwt认证 在不改变原有方法的基础上,添加自己的业务逻辑。相当于grpc中的拦截器一样,在不改变grpc请求的同时,插入自己的业务。 简单例子 func Sum(a, b int) int {return a b }func LoggerMiddleware(in func(a, b int) int) f…...
如何快速制作令人惊叹的长图海报
在当今的数字时代,制作一张吸引人的长图海报已成为许多人的需求。无论是为了宣传活动,还是展示产品,一张设计精美的长图海报都能引起人们的注意。下面,我们将介绍一种简单的方法,使用在线海报制作工具来创建长图海报。…...
D (1092) : DS循环链表—约瑟夫环(Ver. I - A)
Description N个人坐成一个圆环(编号为1 - N),从第S个人开始报数,数到K的人出列,后面的人重新从1开始报数。依次输出出列人的编号。 例如:N 3,K 2,S 1。 2号先出列,然…...
Python爬虫(二十二)_selenium案例:模拟登陆豆瓣
本篇博客主要用于介绍如何使用seleniumphantomJS模拟登陆豆瓣,没有考虑验证码的问题,更多内容,请参考:Python学习指南 #-*- coding:utf-8 -*-from selenium import webdriver from selenium.webdriver.common.keys import Keysimp…...
1. Flink程序打Jar包
文章目录 步骤注意事项 步骤 用 maven 打 jar 包,需要在 pom.xml 文件中添加打包插件依赖 <build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><ver…...
水波纹文字效果动画
效果展示 CSS 知识点 text-shadow 属性绘制立体文字clip-path 属性来绘制水波纹 工具网站 CSS clip-path maker 效果编辑器 页面整体结构实现 使用多个 H2 标签来实现水波纹的效果实现,然后使用clip-path结合动画属性一起来进行波浪的起伏动画实现。 <div …...
【1.1】神经网络:关于神经网络的介绍
✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏: 神经网络(随缘更新) ✨特色…...
java项目中git的.ignore文件设置
在Git中,ignore是用来指定Git应该忽略的故意不被追踪的文件。它并不影响已经被Git追踪的文件。我们可以通过.ignore文件在Git中指定要忽略的文件。 当我们执行git add命令时,Git会检查.gitignore文件,并自动忽略这些文件和目录。这样可以避免…...
11.3 读图举例
一、低频功率放大电路 图11.3.1所示为实用低频功率放大电路,最大输出功率为 7 W 7\,\textrm W 7W。其中 A \textrm A A 的型号为 LF356N, T 1 T_1 T1 和 T 3 T_3 T3 的型号为 2SC1815, T 4 T_4 T4 的型号为 2SD525, T 2…...
黑马JVM总结(二十八)
(1)语法糖-foreach (2)语法糖-switch-string (3)语法糖-switch-enum (4)语法糖-枚举类 枚举类 (5)语法糖-twr1...
2023年DDoS攻击发展趋势的分析和推断
DDoS是一种非常“古老”的网络攻击技术,随着近年来地缘政治冲突对数字经济格局的影响,DDoS攻击数量不断创下新高,其攻击的规模也越来越大。日前,安全网站Latest Hacking News根据DDoS攻击防护服务商Link11的统计数据,对…...
RT-Thread 内存管理(学习二)
内存堆管理应用示例 这是一个内存堆的应用示例,这个程序会创建一个动态的线程,这个线程会动态申请内存并释放,每次申请更大的内存,当申请不到的时候就结束。 #include <rtthread.h>#define THREAD_PRIORITY 25 #defi…...
厦门微信网站建/今天新闻
如图所示: 如果此时给.div1添加属性 position属性是 .div1就会消失不见 那么此时就必须显示给.div1加上宽度,才能显示出来结果如图所示:转载于:https://blog.51cto.com/11871779/2072041...
wordpress站点路径/网站运营指标
1.设定文件系统配额,只能针对磁盘独自分区的文件系统 不能针对文件 目录 未分区磁盘 <1>.实现home家目录的迁移 迁移之前实行备份 --新建一分区sdc2 --创建文件系统 --创建目录并挂载 --拷贝 --切换单一模式 备份后删除以前家目录 并将挂载写入/etc/fstab --重…...
海珠营销型网站建设/免费推广渠道有哪些
前两天刚刚装了一个MyEclipse,今天用了一下,却发现,每次想要在控制台上输出中文时,总是以乱码显示的。查了很多资料,对算是搞明白,怎么回事。首先,在这里先解释下,MyEclipse…...
东莞网站建设技术支持/北京有限公司
目录 题目 思路 考点 Code 题目 中秋节,公司分月饼,m个员工,买了n个月饼,m<=n,每个员工至少分1个月饼,但可以分多个,单人份到最多月饼的个数为Max1,单人分到第二多月饼的个数是Max2,Max1-Max2<=3,。同理,单人分到第n-1多月饼的个数是Max(n-1),单人分到第n…...
江门电商网站设计培训/帮人推广的平台
本文章首发于浩瀚先森博客,地址: http://www.guohao1206.com/2016/08/23/967.html samba时一款为了实现linux系统中的文件能在windows系统中正常访问的软件,分为服务器端和客户端,按照下列方法安装samba服务器即可在windows系统中访问linux系统中的文件。…...
怎么做网站编辑/成都seo培训
6.5.1. 关于LDAP身份验证 Lightweight Directory Access Protocol (LDAP)是一个开放的,中立的,工业标准的应用协议,通过IP协议提供访问控制和维护分布式信息的目录信息。 LDAP服务可视为一种特殊的数据库服务,就像文件系统的目录…...