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

【Rust】枚举和模式匹配——Rust语言基础14

文章目录

  • 1. 枚举类型
    • 1.2. Option 枚举
  • 2. match 控制流结构
    • 2.1. match 对绑定值的匹配
    • 2.2. Option<T> 的匹配
    • 2.3. 通配模式以及 _ 占位符
  • 3. if let 控制流
  • 4. 小测试

1. 枚举类型

枚举(enumerations),也被称作 enums。枚举允许你通过列举可能的成员(variants)来定义一个类型。首先,我们会定义并使用一个枚举来展示它是如何连同数据一起编码信息的。枚举类型可以看作是一个类型的集合。

例如下面这样定义一个枚举:

enum Lunch {duck,rabbit,chicken,
};

对没错,上面的例子展示了一个经典的鸡兔同笼的场景。

问题:笼子里有3只鸡,6只鸭子,5只兔子,请问为什么有37只脚?
答:因为有一只鸡在独立。

问题:笼子里有3只鸡,6只鸭子,5只兔子,请问为什么有36只脚?
答:因为有两只鸡在独立!
回答错误!!
正确回答:因为有一只鸡在睡觉没看到脚。

好了,开个玩笑,定义一个枚举变量就像上面一样简单。

如下便是使用枚举变量的示例:

	let goku = Lunck::chichen;let kuririn = Lunck::duck;

相信有其他编程语言基础的同学对此一定不会陌生,不过更有趣的是,在 rust 中的枚举变量的成员几乎可以指定为任何类型,就像下面这样使用。

    enum IpAddr {V4(u8, u8, u8, u8),V6(String),}let home = IpAddr::V4(127, 0, 0, 1);let loopback = IpAddr::V6(String::from("::1"));

亦或者是这样。

enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}

这些类型的指定都是被 rust 所允许的。请告诉我你们没有忘记这些类型代表什么意义吧~,好吧忘了也没关系,再来复习一次:

  • Quit 没有关联任何数据。
  • Move 类似结构体包含命名字段。
  • Write 包含单独一个 String
  • ChangeColor 包含三个 i32

上面的枚举类型等同于多个结构体类型的定义:

struct QuitMessage; // 类单元结构体
struct MoveMessage {x: i32,y: i32,
}
struct WriteMessage(String); // 元组结构体
struct ChangeColorMessage(i32, i32, i32); // 元组结构体

这样看枚举在一定程度上是会比结构体要方便多了,而且枚举变量同样可以通过 impl 块来定义属于该枚举的方法:

    impl Message {fn call(&self) {// 在这里定义方法体}}let m = Message::Write(String::from("hello"));m.call();

1.2. Option 枚举

Option 也是一个枚举类型,在 rust 中没有空值 Null 的概念,由于考虑到所有变量都存在一种空值和非空值的状态会为编程语言带了巨大问题甚至是会引起各种漏洞,因此 rust 摒弃了这一设计理念,但由于空值同时也具有特殊意义,又会为编程带来很多便利,取而代之则衍生出 Option 这样的枚举。

rust 标准库中是这样定义的:

enum Option<T> {None,Some(T),
}

这里的 <T> 语法是一个泛型参数,虽然目前还没学习到,但相信大家也不陌生,泛型在其它编程语言中也是很常见和重要的存在。这里的 None 就表示没有值,一定程度上等价于 Null 的作用。

2. match 控制流结构

Rust 有一个叫做 match 的极为强大的控制流运算符,它允许我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;。match 的力量来源于模式的表现力以及编译器检查,它确保了所有可能的情况都得到处理。

假设有这样一个场景,现在要上海陆家嘴举办 2025 年天下第一武道大会,邀请了:

  • 埼玉《一拳超人》
  • 五条悟《咒术回战》
  • 孙悟空《七龙珠》
  • 漩涡鸣人《火影忍者》
  • 贝吉塔《七龙珠》
  • 蒙奇·D·路飞《海贼王》

这些著名高手来参加,现在要根据这些选手的战斗能力为他们做排名。

enum Hero {Saitama,Satoru,Goku,Naruto,Bejita,Ruffy,
}fn rank(hero: Hero) -> u8 {match hero {Hero:Saitama => 1,Hero:Satoru=> 2,Hero:Goku=> 3,Hero:Naruto=> 4,Hero:Bejita=> 5,Hero:Ruffy=> 6,}
}

[注]:这里主持人给的排名仅作为参考,并不具备实际意义,请根据大家自己内心估值来判断。也不要问为什么没有请某某某来,上海市举办方表示资金有限,请不起所有高手聚集此地。

好了,根据上面的简单例子相信各位也能够对 match 的功能了解一二,这里就有人站出来说了“这?这不就是 switch & case 语句嘛~”,欸,差不多,但是 rustmatch 要更加强大一点,请继续往下看。

2.1. match 对绑定值的匹配

正如上文提到,枚举变量可以为其成员指定几乎任何类型,对这种情况 match 该如何应对?

enum Hero {Saitama(i32),Satoru(i32),Goku(i32),Naruto(i32),Bejita(i32),Ruffy(i32),
}
// 整数表示其战斗力数值fn power(hero: Hero) {match hero {Hero::Saitama(p) => {println!("埼玉: {}", p);},Hero::Satoru(p) => {println!("五条: {}", p);},Hero::Goku(p) => {println!("悟空: {}", p);},Hero::Naruto(p) => {println!("鸣人: {}", p);},Hero::Bejita(p) => {println!("王子: {}", p);},Hero::Ruffy(p) => {println!("草帽小子: {}", p);},}
}fn main() {let goku = Hero::Goku(12000);power(&goku);
}

rust 中允许这样的匹配,正如上述例子中,将会匹配到 goku 属于 Hero::Goku(p) 类型,并同时将其值绑定到了 p 变量,这样就可以获取其战斗力数值了。

2.2. Option 的匹配

比如我们想要编写一个函数,它获取一个 Option<i32> ,如果其中含有一个值,将其加一。如果其中没有值,函数应该返回 None 值,而不尝试执行任何操作。

得益于 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)。接着将其与每个分支比较。

            None => None,

Some(5) 并不匹配模式 None,所以继续进行下一个分支。

            Some(i) => Some(i + 1),

Some(5)Some(i) 匹配吗?当然匹配!它们是相同的成员。i 绑定了 Some 中包含的值,所以 i 的值是 5。接着匹配分支的代码被执行,所以我们将 i 的值加一并返回一个含有值 6 的新 Some

需要注意的一点是,match 匹配是穷举匹配,必须要为所有可能的结果编写对应的匹配处理过程,否则编译器将会阻止这种情况。

2.3. 通配模式以及 _ 占位符

将上面的代码做以简单改动:

enum Hero {Saitama(i32),Satoru(i32),Goku(i32),Naruto(i32),Bejita(i32),Ruffy(i32),
}
// 整数表示其战斗力数值fn power(hero: Hero) {match hero {Hero::Saitama(p) => {println!("埼玉: {}", p);},Hero::Satoru(p) => {println!("五条: {}", p);},other => {// _ => {	// 与上一行代码等价println!("战斗能力未知!!!");},}
}fn main() {let goku = Hero::Goku(12000);power(&goku);
}

最后一个分支则涵盖了所有其他可能的值,模式是我们命名为 other 的一个变量。

3. if let 控制流

这个语法很像 C/C++ 中的 if 语句,因此掌握起来也非常容易,还是照例给个例子看的比较直白一些:

enum Hero {Saitama(i32),Satoru(i32),Goku(i32),Naruto(i32),Bejita(i32),Ruffy(i32),
}fn main() {let goku = Hero::Goku(12000);//power(&goku);//if let Hero::Goku(p) = goku {println!("悟空: {}", p);} else {println!("战斗能力未知!!!");}}

相信这样简单的例子大家一看便能够明了,当 if let 的条件成立将会进入下方代码块,否则不会,就是这样简单的语句。

4. 小测试

这样以来,条件控制语句我们也掌握的差不多了,看完了,也懂了,让我们试着用一下吧。

接下来我们要实现一个这样的场景,接着上面天下第一武道大会结束之后,还是这些参赛选手们听闻孙悟空会一个绝技“融合”!每个人都很感兴趣,都希望试试自己与另外一个人融合之后会产生什么样的现象。

假设融合对象只能是如下:

  • 五条悟 & 漩涡鸣人
    [注]:大招应该就叫做 “领域展开·风遁大玉尾兽螺旋丸”
  • 埼玉 & 路飞
    [注]:大招应该叫做 “尼卡形态·Jet 认真一拳”
  • 孙悟空 & 贝吉塔
    [注]:大招应该叫做 “冲天咔麦咔麦哈”
  • 其它情况则融合失败。
impl Hero {fn fusion(&self, other: &Hero) -> Hero {match self {Hero::Saitama(p) | Hero::Ruffy(p) => {Hero::Saiffy(self.get() + other.get(), String::from("saitama&ruffy"))},Hero::Satoru(p) | Hero::Naruto(p) => {Hero::Natoru(self.get() + other.get(), String::from("satoru&naruto"))},Hero::Goku(p) | Hero::Bejita(p) => {Hero::Gojita(self.get() + other.get(), String::from("goku&bejita"))},other => {println!("融合失败!!!");Hero::NULL},}}fn get(&self) -> &i32 {match self {Hero::Saitama(p) => p,Hero::Satoru(p) => p,Hero::Goku(p) => p,Hero::Naruto(p) => p,Hero::Bejita(p) => p,Hero::Ruffy(p) => p,other => &0,}}
}#[derive(Debug)]
enum Hero {Saitama(i32),Satoru(i32),Goku(i32),Naruto(i32),Bejita(i32),Ruffy(i32),NULL,Gojita(i32, String),Natoru(i32, String),Saiffy(i32, String),
}fn main() {let goku = Hero::Goku(12000);let bejita = Hero::Bejita(16000);let gojita = Hero::fusion(&goku, &bejita);println!("goku+bejita = {:?}", gojita);
}

[注]:上面代码仅供读者参考,希望大家能够实现出更加有趣的代码~

下一篇《【Rust】包和模块管理,以及作用域等问题——Rust语言基础15》


觉得这篇文章对你有帮助的话,就留下一个赞吧v*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品采用知识共享署名-非商业性-相同方式共享 4.0 国际许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/146249359


http://www.mrgr.cn/news/95036.html

相关文章:

  • Git 使用SSH登陆
  • 漏洞挖掘—EDU SRC证书站漏洞挖掘记录
  • Bellman_ford 算法--带负权值的单源最短路问题,边列表存储
  • C#实现分段三次Hermite插值
  • C语言之数据结构:链表(一)
  • 基于x11vnc的ubuntu远程桌面
  • numpy学习笔记5:arr.T 是数组的转置属性详细解释
  • Blender4.3雕刻笔刷简介
  • numpy学习笔记8:数组属性和基础操作的详细描述
  • 20. Excel 自动化:Excel 对象模型
  • 《TCP/IP网络编程》学习笔记 | Chapter 19:Windows 平台下线程的使用
  • 深度学习框架PyTorch——从入门到精通(6.1)自动微分
  • 股票查询系统
  • nginx配置反向代理数据库等插件的原理和方式
  • ngx_url_t
  • C语音组播收发
  • numpy学习笔记2:ones = np.ones((2, 4)) 的详解
  • ASP4644四通道降压稳压器的工业高效电源管理方案
  • numpy学习笔记6:np.sin(a) 的详细解释
  • 卷积神经网络 - 卷积层