【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.rhkb.cn/news/36091.html

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

相关文章

vs2017版本与arcgis10.1的ArcObject SDK for .NET兼容配置终结解决方案

因电脑用的arcgis10.1,之前安装的vs2010正常能使用AO和AE&#xff0c;安装vs2017后无法使用了&#xff0c;在重新按照新版本arcgis engine或者arcObject费时费力&#xff0c;还需要重新查找资源。 用vs2017与arc10.1的集成主要两个问题&#xff0c;1&#xff1a;安装后vs中没有…

C语言和C++到底有什么关系?

C 读作“C 加加”&#xff0c;是“C Plus Plus”的简称。 顾名思义&#xff0c;C 就是在 C 语言的基础上增加了新特性&#xff0c;玩出了新花样&#xff0c;所以才说“Plus”&#xff0c;就像 Win11 和 Win10、iPhone 15 和 iPhone 15 Pro 的关系。 C 语言是 1972 年由美国贝…

企业微信群聊机器人开发

拿到机器人hook 机器人开发文档 https://developer.work.weixin.qq.com/document/path/91770

AT指令集-NBIOT

是什么&#xff1f; 窄带物联网&#xff08;Narrow Band Internet of Things, NB-IoT&#xff09;成为万物互联网络的一个重要分支支持低功耗设备在广域网的蜂窝数据连接&#xff0c;也被叫作低功耗广域网(LPWAN)NB-IoT支持待机时间长、对网络连接要求较高设备的高效连接NB-Io…

网络爬虫【爬虫库urllib】

我叫不三不四&#xff0c;很高兴见到大家&#xff0c;欢迎一起学习交流和进步 今天来讲一讲爬虫 urllib介绍 Urllib是Python自带的标准库&#xff0c;无须安装&#xff0c;直接引用即可。 Urllib是一个收集几个模块来使用URL的软件包&#xff0c;大致具备以下功能。 ● urlli…

vue中js简单创建一个事件中心/中间件/eventBus

vue中js简单创建一个事件中心/中间件/eventBus 目录结构如下&#xff1a; eventBus.js class eventBus {constructor() {this.events {};}// 监听事件on(event, callback) {if (!this.events[event]) {this.events[event] [];}this.events[event].push(callback);}// 发射…

弹球小游戏-简单开发版

一、需求 弹球小游戏是一个简单的互动游戏&#xff0c;玩家需要控制一个挡板在窗口底部左右移动&#xff0c;以接住从上方落下的球。游戏的主要需求包括&#xff1a; (1) 游戏界面 &#xff1a;创建一个指定尺寸的游戏窗口&#xff0c;显示球和挡板。 (2) 球的运动 &#xf…

Cursor与Blender-MCP生成3D模型

随着DeepSeek的热度&#xff0c;各行各业接入AI智能&#xff0c;当然作为一个深受3D爱好者喜爱的软件——Blender&#xff0c;也接入了AI智能&#xff0c;通过Blender-MCP&#xff0c;开启一场Blender的智能化模型创建的世界之旅。 目录 1.准备工作2.环境配置2.1 Mac安装2.2 W…

简单以太网配置

display arp //查看路由器mac地址 交换机配置命令&#xff1a; system-view // 从用户视图进入系统视图 dis mac-address //查看mac地址表 路由器配置命令: system-view // 从用户视图进入系统视图 int GigabitEthernet 0/0/0 //进入G口 0/0/0 进入之后配置网关: ip addre…

SpringBoot可以同时处理多少请求?

大家好&#xff0c;我是锋哥。今天分享关于【SpringBoot可以同时处理多少请求&#xff1f;】面试题。希望对大家有帮助&#xff1b; SpringBoot可以同时处理多少请求&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 Spring Boot 本身并不直接限制可以处…

一、初始 Linux

文章目录 一、操作系统概述二、Linux 初识1. Linux 的组成2. Linux 发行版 三、远程链接 Linux 系统1. 四、WSL (windows subsystem for linux)1. 什么是 WSL2. 如何下载 WSL3. 安装不同的 Linux 发行版4. 启动停止使用指定发行版5. 卸载与备份6. 文件共享7. 命令混用8. 用 vsc…

LogicFlow介绍

LogicFlow介绍 LogicFlow是一款流程图编辑框架&#xff0c;提供了一系列流程图交互、编辑所必需的功能和灵活的节点自定义、插件等拓展机制。LogicFlow支持前端自定义开发各种逻辑编排场景&#xff0c;如流程图、ER图、BPMN流程等。在工作审批流配置、机器人逻辑编排、无代码平…

Flask实时监控:打造智能多设备在线离线检测平台(升级版)

前言 武林之中&#xff0c;最讲究的便是“掌控”。若是手下弟子忽然失踪&#xff0c;若是江湖好友生死未卜&#xff0c;岂不令人寝食难安&#xff1f;今日&#xff0c;吾等化身技术侠客&#xff0c;祭出Flask实时监控大法&#xff0c;打造一款智能多设备在线离线检测平台&…

嵌入式编程优化技巧:do-while(0)、case范围扩展与内建函数

在嵌入式编程中,优化代码的性能和可靠性至关重要。无论是通过优化控制结构、提升代码的执行效率,还是利用编译器提供的内建函数来加速关键任务,开发者都需要掌握各种技巧和方法。本文将探讨三种在嵌入式编程中常用的优化技术:do-while(0)的使用、case范围扩展以及内建函数的…

MySQL开发陷阱与最佳实践:第1章:MySQL开发基础概述-1.1 MySQL简介与应用场景

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 MySQL开发陷阱与最佳实践&#xff1a;第1章&#xff1a;MySQL开发基础概述-1.1 MySQL简介与应用场景1.1.1 MySQL的发展历程与市场地位1.1.2 MySQL的核心特性与技术优势1.1.2…

Android Audio基础(18)——最小缓冲区

在创建 AudioTrack 时有一个缓冲区大小的参数&#xff0c;最小缓冲区参数通过 AudioTrack.getMinBufferSize() 获取。 一、最小缓冲区 为了让音频数据通路能正常运转&#xff0c;共享FIFO必须达到最小缓冲区的大小。如果数据缓冲区分配得过小&#xff0c;那么播放声音会频繁遭…

Vue:Vue2和Vue3创建项目的几种常用方式以及区别

前言 Vue.js 和 Element UI 都是用 JavaScript 编写的。 1、Vue.js 是一个渐进式 JavaScript 框架。2、Element UI 是基于 Vue.js 的组件库。3、JavaScript 是这两个项目的主要编程语言。 而Element Plus是基于TypeScript开发的。 一、Vue2 1、基于vuecli工具创建 vue2 …

游戏成瘾与学习动力激发策略研究——了解“情感解离”“创伤理论”

一、情感解离(Emotional Dissociation) 定义:情感解离是一种心理防御机制,指个体在经历无法承受的情绪压力或创伤时,通过切断情感体验与认知、记忆或现实感知的联系来保护自我。它不是简单的“麻木”,而是大脑为应对极端刺激而启动的“紧急逃生通道”。 核心特征 1、意…

WPF跨平台开发探讨:借助相关技术实现多平台应用

WPF跨平台开发探讨&#xff1a;借助相关技术实现多平台应用 一、前言二、WPF 跨平台开发的现状与挑战2.1 WPF 的平台局限性2.2 跨平台开发面临的挑战 三、实现 WPF 跨平台开发的相关技术3.1.NET MAUI 简介3.2.NET MAUI 的关键特性3.3 其他相关技术和工具 四、借助.NET MAUI 实现…

ImGui 学习笔记(五) —— 字体文件加载问题

ImGui 加载字体文件的函数似乎存在编码问题&#xff0c;这一点可能跟源文件的编码也有关系&#xff0c;我目前源文件编码是 UTF-16。 当参数中包含中文字符时&#xff0c;ImGui 内部将字符转换为宽字符字符集时候&#xff0c;采用的 MultiByteToWideChar API 参数不太对&#…