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

打印 上一主题 下一主题

主题 881|帖子 881|积分 2643

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

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


 
 
 

 
 
三、示例

书本上的例子非常完满,下例的内容根本摘自书本上,少量做了一些增改。
  1. struct Point {
  2.     x: i32,
  3.     y: i32,
  4. }
  5. #[allow(unused)]
  6. enum Message {
  7.     Quit,
  8.     Move { x: i32, y: i32 },
  9.     Write(String),
  10.     ChangeColor(i32, i32, i32),
  11. }
  12. #[allow(unused)]
  13. enum Color{
  14.     Red,
  15.     Green,
  16.     OtherRgb(i32, i32, i32),
  17. }
  18. #[allow(unused)]
  19. enum Work{
  20.     Start,
  21.     Stop,
  22.     Pause(String),
  23.     Cancel(Color),
  24.     Finish
  25. }
  26. // 为了避免烦人的提示,直接在main函数上添加#[allow(unused)]注解,避免编译器提示未使用警告。
  27. #[allow(unused)]
  28. fn main() {
  29.     //以下例子基本从书本上复制而来
  30.     // 一、解构  -------------------------------------------------------------
  31.     //1. match 匹配字面值。 这是匹配中最简单的
  32.     let x = 1;
  33.     match x {
  34.         1 => println!(" x is 壹"),
  35.         2 => println!(" x is 贰"),
  36.         3 => println!(" x is 叁"),
  37.         _ => println!(" x is 其它"),
  38.     }
  39.     //2. match匹配命名变量。 它的主要作用是捕获变量,以便打印或者他用
  40.     let x = Some(5);
  41.     let y = 10;
  42.     match x {
  43.         Some(50) => println!("Got 50"),
  44.         Some(y) => println!("Matched, y = {y}"),
  45.         _ => println!("Default case, x = {:?}", x),
  46.     }
  47.     //3. match 匹配多个值. 多个值可以用 | 分隔 .这是属于散列值匹配
  48.     let x = 1;
  49.     match x {
  50.         1 | 2 => println!("小于3的正整数"),
  51.         3 => println!("燕子三抄水"),
  52.         _ => println!("不知所云...."),
  53.     }
  54.     //4. match 匹配区间值. 值区间使用..表示。 ..=表示区间匹配
  55.     let x = 5;
  56.     match x {
  57.         1..=5 => println!("1-5之间的正整数"),
  58.         _ => println!("其它"),
  59.     }
  60.     //5. 解构结构体  let语法. 还可以在主域中创建不在主域中定义的变量
  61.     //凭空在主域创建变量 a,b。 按照其它语言的习惯,谁看了不迷茫!!!
  62.     let p = Point { x: 0, y: 7 };
  63.     let Point { x: a, y: b } = p;
  64.     assert_eq!(0, a);
  65.     assert_eq!(7, b);
  66.     //和match枚举一样,也可以通过match捕获结构体的字段。
  67.     //在match子域内部创建变量x,y(捕获)
  68.     let p = Point { x: 99, y: 7 };
  69.     match p {
  70.         Point { x, y } => println!("坐标为({x},{y})"),
  71.     }
  72.     //6. 解构枚举,此类解构类似于match中解构结构体
  73.     let msg = Message::ChangeColor(0, 160, 255);
  74.     match msg {
  75.         Message::Quit => {
  76.             println!("The Quit variant has no data to destructure.");
  77.         }
  78.         Message::Move { x, y } => {
  79.             println!("Move in the x direction {x} and in the y direction {y}");
  80.         }
  81.         Message::Write(text) => {
  82.             println!("Text message: {text}");
  83.         }
  84.         Message::ChangeColor(r, g, b) => {
  85.             println!("Change the color to red {r}, green {g}, and blue {b}")
  86.         }
  87.     }
  88.     //7. 解构嵌套的结构体、枚举  -- 这个操作还是类似于利用match解构结构体
  89.     let laugh=Work::Cancel(Color::OtherRgb(100,99,98));
  90.     match laugh{
  91.         Work::Cancel(Color::OtherRgb(r,g,b))=>{
  92.             println!("r:{r},g:{g},b:{b}");
  93.         }
  94.         _=>{}
  95.     }
  96.     //8.解构结构体和元组  -
  97.     // 找不到理想的例子,用了书本上的.
  98.     // 不太明白,这个算什么解构结构体和元组。 不如说解构元组吧
  99.     let ((feet, inches), Point { x, y }) = ((3, 10), Point { x: 3, y: -10 });
  100.     //来个解构元组的例子
  101.     let tup = (1, 2, 3);
  102.     let (a, b, c) = tup;
  103.     println!("元组tmp中的三个值分别是-a:{a},b:{b},c:{c}");
  104.     // 二.忽略  ------------------------------------------------------------------------
  105.    
  106.     //9.0 使用_忽略整个值 (方法或者函数的参数)
  107.     ignore_test(92,202);
  108.    
  109.     //10. 使用嵌套的_忽略部分值  (实际上还是忽略所有值)
  110.     let mut setting_value = Some(5);
  111.     let new_setting_value = Some(10);
  112.     match (setting_value, new_setting_value) {
  113.         (Some(_), Some(_)) => {
  114.             println!("Can't overwrite an existing customized value");
  115.         }
  116.         _ => {
  117.             setting_value = new_setting_value;
  118.         }
  119.     }
  120.     println!("setting is {setting_value:?}");
  121.     // 10.1 这个匹配元组的稍微有点意思
  122.     // 在rust,解构数据的部分为变量的时候,就意味着隐式定义了这样的一个变量
  123.     // 例如下例中,n1,n3,n5 就是隐式定义的变量。后面的编码就尽量不要覆盖它们。
  124.     // 根据这样的趋势,是不是rust让所有类型都可以模式匹配,例如数组
  125.     let numbers = (2, 4, 8, 16, 32);
  126.     match numbers {
  127.         (n1, _, n3, _, n5) => {
  128.             println!("Some numbers: {n1}, {n3}, {n5}")
  129.         }
  130.     }
  131.     //10.2 数组的匹配
  132.     let foods=["水","大米","萝卜","白菜"];
  133.     match foods{
  134.         [first,_,_,third]=>{
  135.             println!("Some foods:{first},{third}");
  136.         }
  137.         _=>{}
  138.     }
  139.     //10.3 匹配向量  -- 这个好像不行
  140.     // let books=vec!["诗经","春秋","论语"];
  141.     // match books{
  142.     //     [b1,b2,b3]=>{
  143.     //         println!("Some books:{b1},{b2},{b3}");
  144.     //     }
  145.     // }
  146.     //11. 变量以下划线开头,以忽略不用警告 --  即一个下划线开头的变量,即使你没有使用,rustc也不会警告。否则会的
  147.     // warning: unused variable: `sex`
  148.     let  _sex="男";
  149.     let  age=99;
  150.     //12. 在匹配的时候,使用..跳过不想匹配的部分  。 这个作用和下划线有点类似,不过前者针对变量个数,后者针对具体变量的值范围
  151.     match foods{
  152.         [这是地瓜,..]=>{
  153.             println!("第一格的食物是:{这是地瓜}");
  154.         }      
  155.     }
  156.     // 三、条件 -----------------------------------------------------------------------
  157.     //13.匹配守卫 -- 类似于if的条件判断 .不如称为匹配条件
  158.     //利用匹配条件,可能会导致有些分支丢失的情况。但rustc不会报告异常,这个需要开发者自己注意。
  159.     //13.1 条件中使用当前变量
  160.     let x = Some(5);
  161.     match  x {
  162.        Some(z) if z>10=>{
  163.            println!("Some(z) is greater than 10");
  164.        }
  165.        _=>{
  166.            println!("Some(z)  小于等于 10");
  167.        }
  168.     }
  169.     //13.2 条件中使用其它变量
  170.     let x = 4;
  171.     let y = false;
  172.     match x {
  173.         4 | 5 | 6 if y => println!("yes"),
  174.         4 | 5 | 6 if !y => println!("no"),   //这一句如果不写,那么这个match会有丢失的分支
  175.         _ => println!("其它情况"),
  176.     }
  177.     //14. @绑定, 是一个类似匹配套件的东西,只不过这个主要为枚举服务,且其表达式是比较简单,只能给一个范围?
  178.     //有两种语法 val: val @ n..=m 或者 val @ n..m   .自然后面一种更加友好一些
  179.     let mywork=Work::Cancel(Color::OtherRgb(100,99,98));
  180.     match mywork{
  181.         Work::Cancel(Color::OtherRgb( r @99..104,g,b))=>{
  182.             println!("r:{r},g:{g},b:{b}");
  183.         },
  184.         _=>{
  185.             println!("其它情况");
  186.         }
  187.     }
  188.     match mywork{
  189.         Work::Cancel(Color::OtherRgb( r @1..90,g,b))=>{
  190.             println!("r:{r},g:{g},b:{b}");
  191.         },
  192.         _=>{
  193.             println!("其它情况");
  194.         }
  195.     }
  196. }
  197. fn ignore_test(_: i32, y: i32){
  198.     println!("y:{y}");
  199.     // 这个参数_无法访问。不知道rust搞这个有何意义
  200.     //println!("忽略参数:{}",_);
  201. }
复制代码
 
效果输出不是很友好,但是也能看:

 
四、小结

rust的模式匹配的确是特别的体验,在以往学过的多种编程语言中,没有遇到那么多的。
固然,这在某些时间带来了不少方便,但是对于某些工程师而言并不是太友好,至少初期不是那么友好。
要说不友好,好像又不是,因为用了其中的一些匹配方式,获取对象中的值还是有点方便的。
总之,这种计划体现了rust语言的计划师的思维本领-更加灵活复杂,但又轻微显得凌乱。 
 
在我个人的想象中,无论什么技术,最后应该都应该看起来简单优雅。
当我们学习rust的时间,这个关卡必须迈过,否则很多代码还是无法读懂的。
 

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

羊蹓狼

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表