rust学习十九.1、模式匹配(match patterns)

news/2025/2/22 19:43:23/文章来源:https://www.cnblogs.com/lzfhope/p/18729758

本章节大概是书本上比较特殊一个,因为它没有什么复杂的内容,通篇主要讨论模式匹配的语法。

一、两个名词

  a.可反驳 -    refutable  
    对某些可能的值进行匹配会失败的模式被称为是 可反驳的(refutable)
    let Some(x) = some_option_value;如果 some_option_value 的值是 None,其不会成功匹配模式 Some(x)
  b.不可反驳 -irrefutable
     能匹配任何传递的可能值的模式被称为是 不可反驳的(irrefutable)。
     一个例子就是 let x = 5; 语句中的 x,因为 x 可以匹配任何值所以不可能会失败

二、脑图汇总

 

 

 

 

 

三、示例

书本上的例子非常完善,下例的内容基本摘自书本上,少量做了一些增改。

struct Point {x: i32,y: i32,
}
#[allow(unused)]
enum Message {Quit,Move { x: i32, y: i32 },Write(String),ChangeColor(i32, i32, i32),
}
#[allow(unused)]
enum Color{Red,Green,OtherRgb(i32, i32, i32),
}
#[allow(unused)]
enum Work{Start,Stop,Pause(String),Cancel(Color),Finish
}
// 为了避免烦人的提示,直接在main函数上添加#[allow(unused)]注解,避免编译器提示未使用警告。
#[allow(unused)]
fn main() {//以下例子基本从书本上复制而来// 一、解构  -------------------------------------------------------------//1. match 匹配字面值。 这是匹配中最简单的let x = 1;match x {1 => println!(" x is 壹"),2 => println!(" x is 贰"),3 => println!(" x is 叁"),_ => println!(" x is 其它"),}//2. match匹配命名变量。 它的主要作用是捕获变量,以便打印或者他用let x = Some(5);let y = 10;match x {Some(50) => println!("Got 50"),Some(y) => println!("Matched, y = {y}"),_ => println!("Default case, x = {:?}", x),}//3. match 匹配多个值. 多个值可以用 | 分隔 .这是属于散列值匹配let x = 1;match x {1 | 2 => println!("小于3的正整数"),3 => println!("燕子三抄水"),_ => println!("不知所云...."),}//4. match 匹配区间值. 值区间使用..表示。 ..=表示区间匹配let x = 5;match x {1..=5 => println!("1-5之间的正整数"),_ => println!("其它"),}//5. 解构结构体  let语法. 还可以在主域中创建不在主域中定义的变量//凭空在主域创建变量 a,b。 按照其它语言的习惯,谁看了不迷茫!!!let p = Point { x: 0, y: 7 };let Point { x: a, y: b } = p;assert_eq!(0, a);assert_eq!(7, b);//和match枚举一样,也可以通过match捕获结构体的字段。//在match子域内部创建变量x,y(捕获)let p = Point { x: 99, y: 7 };match p {Point { x, y } => println!("坐标为({x},{y})"),}//6. 解构枚举,此类解构类似于match中解构结构体let msg = Message::ChangeColor(0, 160, 255);match msg {Message::Quit => {println!("The Quit variant has no data to destructure.");}Message::Move { x, y } => {println!("Move in the x direction {x} and in the y direction {y}");}Message::Write(text) => {println!("Text message: {text}");}Message::ChangeColor(r, g, b) => {println!("Change the color to red {r}, green {g}, and blue {b}")}}//7. 解构嵌套的结构体、枚举  -- 这个操作还是类似于利用match解构结构体let laugh=Work::Cancel(Color::OtherRgb(100,99,98));match laugh{Work::Cancel(Color::OtherRgb(r,g,b))=>{println!("r:{r},g:{g},b:{b}");}_=>{}}//8.解构结构体和元组  - // 找不到理想的例子,用了书本上的.// 不太明白,这个算什么解构结构体和元组。 不如说解构元组吧let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });//来个解构元组的例子let tup = (1, 2, 3);let (a, b, c) = tup;println!("元组tmp中的三个值分别是-a:{a},b:{b},c:{c}");// 二.忽略  ------------------------------------------------------------------------//9.0 使用_忽略整个值 (方法或者函数的参数)ignore_test(92,202);//10. 使用嵌套的_忽略部分值  (实际上还是忽略所有值)let mut setting_value = Some(5);let new_setting_value = Some(10);match (setting_value, new_setting_value) {(Some(_), Some(_)) => {println!("Can't overwrite an existing customized value");}_ => {setting_value = new_setting_value;}}println!("setting is {setting_value:?}");// 10.1 这个匹配元组的稍微有点意思// 在rust,解构数据的部分为变量的时候,就意味着隐式定义了这样的一个变量// 例如下例中,n1,n3,n5 就是隐式定义的变量。后面的编码就尽量不要覆盖它们。// 根据这样的趋势,是不是rust让所有类型都可以模式匹配,例如数组let numbers = (2, 4, 8, 16, 32);match numbers {(n1, _, n3, _, n5) => {println!("Some numbers: {n1}, {n3}, {n5}")}}//10.2 数组的匹配let foods=["","大米","萝卜","白菜"];match foods{[first,_,_,third]=>{println!("Some foods:{first},{third}");}_=>{}}//10.3 匹配向量  -- 这个好像不行// let books=vec!["诗经","春秋","论语"];// match books{//     [b1,b2,b3]=>{//         println!("Some books:{b1},{b2},{b3}");//     } // }//11. 变量以下划线开头,以忽略不用警告 --  即一个下划线开头的变量,即使你没有使用,rustc也不会警告。否则会的// warning: unused variable: `sex`
let  _sex="";let  age=99;//12. 在匹配的时候,使用..跳过不想匹配的部分  。 这个作用和下划线有点类似,不过前者针对变量个数,后者针对具体变量的值范围
    match foods{[这是地瓜,..]=>{println!("第一格的食物是:{这是地瓜}");}       }// 三、条件 -----------------------------------------------------------------------//13.匹配守卫 -- 类似于if的条件判断 .不如称为匹配条件//利用匹配条件,可能会导致有些分支丢失的情况。但rustc不会报告异常,这个需要开发者自己注意。//13.1 条件中使用当前变量let x = Some(5);match  x {Some(z) if z>10=>{println!("Some(z) is greater than 10");}_=>{println!("Some(z)  小于等于 10");}}//13.2 条件中使用其它变量let x = 4;let y = false;match x {4 | 5 | 6 if y => println!("yes"),4 | 5 | 6 if !y => println!("no"),   //这一句如果不写,那么这个match会有丢失的分支_ => println!("其它情况"),}//14. @绑定, 是一个类似匹配套件的东西,只不过这个主要为枚举服务,且其表达式是比较简单,只能给一个范围?//有两种语法 val: val @ n..=m 或者 val @ n..m   .自然后面一种更加友好一些 
let mywork=Work::Cancel(Color::OtherRgb(100,99,98));match mywork{Work::Cancel(Color::OtherRgb( r @99..104,g,b))=>{println!("r:{r},g:{g},b:{b}");},_=>{println!("其它情况");} }match mywork{Work::Cancel(Color::OtherRgb( r @1..90,g,b))=>{println!("r:{r},g:{g},b:{b}");},_=>{println!("其它情况");} }}fn ignore_test(_: i32, y: i32){println!("y:{y}");// 这个参数_无法访问。不知道rust搞这个有何意义//println!("忽略参数:{}",_);
}

 

结果输出不是很友好,但是也能看:

 

四、小结

rust的模式匹配的确是特别的体验,在以往学过的多种编程语言中,没有遇到那么多的。

固然,这在某些时候带来了不少方便,但是对于某些工程师而言并不是太友好,至少初期不是那么友好。

要说不友好,好像又不是,因为用了其中的一些匹配方式,获取对象中的值还是有点方便的。

总之,这种设计体现了rust语言的设计师的思维能力-更加灵活复杂,但又稍微显得凌乱。 

 

在我个人的想象中,无论什么技术,最后应该都应该看起来简单优雅。

当我们学习rust的时候,这个关卡必须迈过,否则很多代码还是无法读懂的。

 

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

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

相关文章

大对数电缆打线顺序

5种线缆主色:白色、红色、黑色、黄色、紫色 5种线缆配色:蓝色、橙色、绿色、棕色、灰色 25对电话电缆色谱线序表30对电话电缆色谱线序 这里要特别说明下:30对的电话电缆要注意了,30对通信电缆里有2种白色的主色,大于25对了就一定要看标识线了!!有一小把是用“白蓝"…

01-springsecurity数据库登录

01 - SpringSecurity实现数据库登录 环境: springboot 3.4.2, springsecurity 6.4.2, mybatis 3.0.4springsecurity中的UserDetails接口用于表示用户信息, 包含用户名、密码等信息。UserDetailsService接口用于加载用户信息, 里边就这一个方法 public interface UserDetailsSer…

【喜与悲】- 2025.2.22 晚

下图为《Balatro》中的一张小丑牌:【喜与悲】喜与悲可以重新触发所有打出的人头牌,是重新触发家族中的一员。但其特性也决定了其强度方差极大,有配合则强度很高,没有配合则纯浪费小丑位。但很少有小丑能与其配合,而能与其配合的小丑大多单独拎出来又不强。更多时候其几乎只…

莫队算法学习笔记

莫队算法的发明者是一个叫做 莫涛 的人,所以被称为莫队算法,简称莫队。 英语 Mos algorithm。 使用场景 莫队算法常常被用来处理多次区间询问的问题,离线处理询问(必须满足!!!)。 插叙:离线是一种得到所有询问再进行计算的方法,是很重要的思想。 对于这种“区间询问”…

参数-返回值-局部变量-数组

参数和局部变量没有本质区别,都是栈中的数据 参数时在函数调用前分配的值,局部变量是在函数调用时分配的值 参数 ebp+* 局部变量 ebp-* 赋值的本质是把运算结果放到某个内存里数组: 一堆连续存储的等宽数据

详细介绍java的线程池状态

一、详细介绍java的线程池状态 Java 中的线程池状态是 ThreadPoolExecutor 类内部管理的一个重要概念。线程池的状态决定了线程池的行为,例如是否接受新任务、是否处理队列中的任务、是否中断正在执行的任务等。 线程池的状态通过一个 AtomicInteger 变量(ctl)来表示,该变量…

[Java SE] Java静态代码块与静态属性的执行顺序

序 重要结论先说结论,再去观察实验现象,印证结论。静态变量初始化和静态代码块的执行顺序是:按照它们在类中出现的顺序进行的。代码实验 实验1import org.slf4j.Logger; import org.slf4j.LoggerFactory;public class JavaStaticTest {private final static String VAR = &qu…

PyTorch TensorBoard 使用

这篇文章介绍如何在 PyTorch 中使用 TensorBoard 记录训练数据。 记录数据 初始化 在程序启动时创建 SummaryWriter 对象用于写入日志数据。 from torch.utils.tensorboard import SummaryWriter import datetime# 获取当前时间戳,一般以时间戳作为记录文件夹名称的一部分 tim…

Svelte 最新中文文档教程(16)—— Context(上下文)

前言 Svelte,一个语法简洁、入门容易,面向未来的前端框架。从 Svelte 诞生之初,就备受开发者的喜爱,根据统计,从 2019 年到 2024 年,连续 6 年一直是开发者最感兴趣的前端框架 No.1:Svelte 以其独特的编译时优化机制著称,具有轻量级、高性能、易上手等特性,非常适合构…

微信小程序-授权获取手机号

前端 wxml <button name=phone class=phone value={{userInfo.phone}} wx:if="{{!userInfo.phone}}" bindgetphonenumber="getPhoneNumber" hover-class=none open-type=getPhoneNumber>点击获取 </button>js import { wxGetPhoneNumber } fr…

Linux 中xargs 中 -L和-n参数的差异

001、-L :按照换行符的数量来传递[root@PC1 dir1]# ls [root@PC1 dir1]# echo {0..9} 0 1 2 3 4 5 6 7 8 9 [root@PC1 dir1]# echo {0..9} | xargs -L 2 ## 利用echo生成一个1行的测试数据 0 1 2 3 4 5 6 7 8 9 [root@PC1 dir1]# seq 0 9 0 1 2 3 4 5 6 7 8 9 [ro…

【humanoid gym】关于在Issac gym里面PPO算法实现里transitions部分roll out storage的记录

1. 前言 一方面便于日后自己的温故学习,另一方面也便于大家的学习和交流。 如有不对之处,欢迎评论区指出错误,你我共同进步学习! 2. 正文 2.1 在on_policy_runner.py文件夹下,初始化的地方:然后我们寻找定义的地方,在ppo.py文件夹下:其中参数num_transitions_per_env其…