Rust-08-枚举和模式匹配

枚举类

结构体给予你将字段和数据聚合在一起的方法,像 Rectangle 结构体有 width 和 height 两
个字段。而枚举给予你将一个值成为一个集合之一的方法。比如,我们想让 Rectangle 是一
些形状的集合,包含 Circle 和 Triangle 。为了做到这个,Rust 提供了枚举类型。

enum BpmKindStatus {DirectManager,DeptManager,
}fn main() {let status = DirectManager;chooseNextUserId(status);
}fn chooseNextUserId(bpm_kind_status: BpmKindStatus) -> i32 {1
}

比如在bpm选择下个人的时候,根据不同的枚举类型选择不同的用户,实际使用中应该是用的数值型和字符串,我们可以使用一种更简洁的方式来表达相同的概念,仅仅使用枚举并将数据直接放进每一个枚举成员而不是将枚举作为结构体的一部分。
优化一下

enum BpmKindStatus {DirectManager(i32,String),DeptManager(i32,String),
}fn main() {let status = DirectManager(10,String::from("部门领导"));chooseNextUserId(status);
}fn chooseNextUserId(bpm_kind_status: BpmKindStatus) -> i32 {1
}

但是在正常的使用中肯定不是这样每个结构体都这样子定义的

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

结构体和枚举还有另一个相似点:就像可以使用 impl 来为结构体定义方法那样,也可以在枚
举上定义方法。这是一个定义于我们 Message 枚举上的叫做 call 的方法:

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

方法体使用了 self 来获取调用方法的值。这个例子中,创建了一个值为Message::Write(String::from(“hello”)) 的变量 m ,而且这就是当 m.call() 运行时 call 方法中的 self 的值。

让我们看看标准库中的另一个非常常见且实用的枚举:Option 。

Option 枚举和其相对于空值的优势

这一部分会分析一个 Option 的案例,Option 是标准库定义的另一个枚举。Option 类型应用广泛因为它编码了一个非常普遍的场景,即一个值要么有值要么没值。没错,很简单的就联想到了java 的 Optional
标准库定义

enum Option<T> {None,Some(T),
}
fn main() {let some_number = Some(5);let some_char = Some('e');let absent_number: Option<i32> = None;}

总的来说,为了使用 Option 值,需要编写处理每个成员的代码。你想要一些代码只当拥有 Some(T) 值时运行,允许这些代码使用其中的 T 。也希望一些代码只在值为 None 时运行,这些代码并没有一个可用的 T 值。match 表达式就是这么一个处理枚举的控制流结构:它会根据枚举的成员运行不同的代码,这些代码可以使用匹配到的值中的数据。

match控制流

可以把 match 表达式想象成某种硬币分类器:硬币滑入有着不同大小孔洞的轨道,每一个硬币都会掉入符合它大小的孔洞。同样地,值也会通过 match 的每一个模式,并且在遇到第一个 “符合” 的模式时,值会进入相关联的代码块并在执行中被使用。

enum Coin {Penny,Nickel,Dime,Quarter,
}
fn value_in_cents(coin: Coin) -> u8 {match coin {Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}
}fn main() {}

这看起来非常像 if 所使用的条件表达式,不过这里有一个非常大的区别:对于 if ,表达式必须返回一个布尔值,而这里它可以是任何类型的。

fn value_in_cents(coin: Coin) -> u8 {match coin {Coin::Penny => {println!("1111");1},Coin::Nickel => 5,Coin::Dime => 10,Coin::Quarter => 25,}
}

绑定值的模式

#[derive(Debug)]
enum CoinType {YuanDaTou,Song,Qin,// --snip--
}
enum Coin {Penny,Nickel,Dime,Dynasty(CoinType)
}fn coin_dynasty(coin:Coin) -> u8 {match coin {Coin::Penny => 1,Coin::Nickel => 5,Coin::Dime => 10,Coin::Dynasty(coinType) => {println!("coin from {:?}!", coinType);25}}
}
fn main() {coin_dynasty(Coin::Dynasty(CoinType::Song));
}

匹配option

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

fn main() {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);
}

将 match 与枚举相结合在很多场景中都是有用的。你会在 Rust 代码中看到很多这样的模式:match 一个枚举,绑定其中的值到一个变量,接着根据其值执行代码。

匹配是穷尽的

match 还有另一方面需要讨论:这些分支必须覆盖了所有的可能性。考虑一下 plus_one 函数
的这个版本,它有一个 bug 并不能编译:

fn plus_one(x: Option<i32>) -> Option<i32> {match x {Some(i) => Some(i + 1),}}

Rust 知道我们没有覆盖所有可能的情况甚至知道哪些模式被忘记了!Rust 中的匹配是 穷尽的:必须穷举到最后的可能性来使代码有效。特别的在这个 Option 的例子中,Rust 防止我们忘记明确的处理 None 的情况。

通配模式和 _ 占位符

通配模式类似于java switch中的default;

fn main() {let dice_roll = 9;match dice_roll {3 => add_fancy_hat(),7 => remove_fancy_hat(),other => move_player(other),}fn add_fancy_hat() {}fn remove_fancy_hat() {}fn move_player(num_spaces: u8) {} // 通配到了other里面
}

当没有变量时使用_

fn main() {let dice_roll = 9;match dice_roll {3 => add_fancy_hat(),7 => remove_fancy_hat(),_=> retur(), // 如果这里不想运行任何方法,使用 _ => (),}fn add_fancy_hat() {}fn remove_fancy_hat() {}fn retur() {} 
}

if let 简洁控制流

if let 语法让我们以一种不那么冗长的方式结合 if 和 let ,来处理只匹配一个模式的值而忽略其他模式的情况。
if let 语法获取通过等号分隔的一个模式和一个表达式。它的工作方式与 match 相同,这里的表达式对应 match 而模式则对应第一个分支。如果你的程序遇到一个使用 match 表达起来过于啰嗦的逻辑,那么可以使用 if let 语法

fn main() {let config_max = Some(3u8);if let Some(max) = config_max {println!("The maximum is configured to be {}", max);} else {// 处理其它逻辑}
}

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

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

相关文章

硬件工程师需要掌握的工具

软件工具&#xff1a; 一、常用画图软件 1、AD/protel 简单好学&#xff0c;在低端市场使用的比较多。建议刚进入硬件工程师岗位或者大学生使用。 2、Candence/allegro Candence画复杂的板子相对更加有优势。但是学习难度比较高&#xff0c;但是如果学会AD后&#xff0c;可…

MSPM0——GPIO的使用

在dl_gpio.h库函数文件中&#xff0c;有三个函数可以控制引脚状态。 __STATIC_INLINE void DL_GPIO_setPins(GPIO_Regs* gpio, uint32_t pins) 该函数为控制引脚输出高电平&#xff0c;按照本例程中LED的引脚&#xff0c;则可以写为 DL_GPIO_setPins(LED1_PORT,LED1_PIN_14_…

适用于电脑的 5 大嗨格式数据恢复替代方案

嗨格式数据恢复是有一定知名度的 Windows 和 Mac 恢复程序&#xff0c;旨在恢复格式化、删除和丢失的图片、视频和音频。该应用程序支持多种文件格式以及相机 RAW 图像。最好的部分&#xff1f;它的预览功能可以在恢复照片和其他媒体文件之前检查和验证它​​们——这可以节省大…

番外篇 | 超越ReLU却鲜为人知,YOLOv5改进之崛起的最佳激活函数GELU!

前言:Hello大家好,我是小哥谈。作为决定神经网络是否传递信息的「开关」,激活函数对于神经网络而言至关重要。不过今天被人们普遍采用的ReLU真的是最高效的方法吗?最近在社交网络上,人们找到了一个看来更强大的激活函数:GELU,这种方法早在2016年即被人提出,然而其论文迄…

快排(快速排序)的递归与非递归实现(文末附完整代码)

快排有几种不同的写法&#xff0c;下面一一来介绍并实现。其中又分为递归和非递归的写法&#xff0c;但大体思路相同&#xff0c;只是代码实现略有不同。(注&#xff1a;文章中的完整代码中&#xff0c;Swap()函数均省略未写&#xff0c;记得自己补充) 递归写法 递归的写法类…

glm-4v-9b 部署

glm-4v-9b 模型文件地址 GLM-4 仓库文件地址 官方测试 硬件配置和系统要求 官方测试硬件信息: OS: Ubuntu 22.04Memory: 512G…

进程概念(二)

目录 进程优先级基本概念查看系统进程PRI and NIPRI vs NI修改进程优先级的命令renice修改优先级进程其他概念 环境变量基本概念查看环境变量方法常见环境变量PATHHOMESHELL 查看环境变量环境变量相关的命令 环境变量特征命令行参数main函数中的俩个参数 argc argvmain函数的第…

LabVIEW缝缺陷图像标注库

LabVIEW缝缺陷图像标注库 开发了一个基于LabVIEW平台构建的船舶焊缝缺陷图像标注库。该库旨在通过高效和简洁的方式处理和标注船舶焊缝缺陷图像&#xff0c;提高缺陷识别的准确性和效率&#xff0c;进而保障船舶的结构安全。 项目背景 在船舶制造过程中&#xff0c;焊接质量…

人工智能和物联网如何结合

欢迎来到 Papicatch的博客 文章目录 &#x1f349;引言 &#x1f349;AI与IoT的结合方式 &#x1f348;数据处理和分析 &#x1f34d;实例 &#x1f348;边缘计算 &#x1f34d;实例 &#x1f348;自动化和自主操作 &#x1f34d;实例 &#x1f348;安全和隐私保护 &…

YOLOv10 超详细解析 | 网络结构、训练策略、论文解读

网络结构 1. Backbone 2. Head 3. 说明 网络结构按 YOLOv10m 绘制&#xff0c;不同 scale 的模型在结构上略有不同&#xff0c;而不是像 YOLOv8 一样仅调整 depth 和 width。Head 有部分后续计算与 YOLOv8 完全相同&#xff0c;上图省略&#xff0c;具体请看此文。YOLOv10 整…

Vue3+Vite报错:vite忽略.vue扩展名 Failed to resolve import ..... Does the file exist?

Vue3Vite报错&#xff1a;vite忽略.vue扩展名 Failed to resolve import … Does the file exist? 先看报错&#xff1a; 分析原因 原因是我们没有写后缀名 建议你在你的vite.config.js中加上如下配置 import { defineConfig } from "vite"; import vue from &qu…

人工智能程序员应该有什么职业素养?

人工智能程序员应该有什么职业素养&#xff1f; 面向企业需求去学习AI必备技能实战能力实战能力提升策略 面向企业需求去学习 如果想要应聘AI相关的岗位&#xff0c;就需要知道HR和管理层在招聘时需要考察些什么&#xff0c;面向招聘的需求去学习就能具备AI程序员该有的职业素…

怀庄之醉酱香白酒的历史(一)——茅台镇的地理位置与名称由来

茅台镇&#xff0c;这个黔北的历史名镇&#xff0c;自古以来就有着“川盐走贵州&#xff0c;秦商聚茅台”的繁荣景象。它坐落于仁怀市城西13公里之处的赤水河东岸&#xff0c;具体地理位置是东经10622′&#xff0c;北纬2751′。这个镇子依山傍水&#xff0c;位于寒婆岭下&…

C++中的宏定义

目录 摘要 1. 条件编译 2. 宏函数 3. 字符串化和连接 4. 可变参数宏 5. 宏和模板结合使用 6. 防止重复包含 7. 复杂宏定义 8. 安全的宏函数 9. 内联宏与内联函数的比较 总结 摘要 C中的宏定义&#xff08;Macros&#xff09;是预处理器的一部分&#xff0c;可以在编…

RJ45 PCB布线

RJ45底盘接地和数字地通过一个1M欧姆的电阻和一个0.1uF的去耦电容隔离。其底盘接地和数字地的间距&#xff0c;必须比60mil宽。如图11及图12所示。 图11 典型变压器集成单RJ45的机箱/数字地平面 图12 典型RJ45和变压器分开的机箱/数字地平面https://www.bilibili.com/read/…

主从式光伏并网发电系统体系结构

通过控制组协同开关&#xff0c;来动态滴决定在不同的外部环境下光伏并网系统的结构&#xff0c;以期望达到最佳的光伏能量利用效率。 当外部光照强度较低时&#xff0c;控制组协同开关使所有的光伏组件只和一个并网逆变器相连&#xff0c;构成为集中式结构&#xff0c;从而克…

flink 作业动态维护更新,不重启flink,不提交作业

Flink任务实时获取并更新规则_flink任务流实时变更-CSDN博客 一种动态更新flink任务配置的方法_flink 数据源 动态更新-CSDN博客 Flink CEP在实时风控场景的落地与优化 最佳实践 - 在SQL任务中使用Flink CEP - 《实时计算用户手册-v4.5.0》 Flink SQL CEP详解-CSDN博客 如…

Java——ArrayList与顺序表

一、线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列&#xff0c;线性表是一种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列... 线性表在逻辑上是线性结构&#xff0c;也就是连续的一条直…

供应链经理面试题

供应链经理面试题通常会涉及对供应链管理的基本理解、工作经验、解决问题的能力以及团队协作等多个方面。 请简要介绍一下你在供应链管理领域的工作经验和取得的成绩。你如何定义供应链管理&#xff1f;它在企业中的作用是什么&#xff1f;你认为供应链经理最重要的职责是什么…

Qt无边框

最简单的可拖动对话框(大小不可改变) #ifndef DIALOG_H #define DIALOG_H/*** file dialog.h* author lpl* brief 无边框dialog类* date 2024/06/05*/ #include <QDialog> #include <QMouseEvent> namespace Ui { class Dialog; } /*** brief The Dialog class* 无…