• 通过match看rust


      

      最常见的逻辑控制流比如if-else,switch,while等常用编程语言都支持,但恰巧rust语法中没有switch,取而代之的是更加强大适用的match匹配,我们就来看看rust的match有何奇特之处。


     一、介绍

    先来看一个简单的rust的match用法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    enum Role{
      Admin,
      User,
      Guest,
      Unkown
    }
     
    fn main(){
      let role=Role::Admin;
      match role{
        Role::Admin=>println!("you're an admin."),
        Role::User=>println!("you're a user."),
        Role::Guest=>println!("you're a guest."),
        _=>println!("deny to access.")
      }
    }

    从这个例子可以看出,rust的match跟其它常用语言的switch功能相似。都是根据条件匹配分支。

    比如C#实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    enum
    {
      Admin,
      User,
      Guest,
      Unkown
    }
     
    void Main(){
      var role=Role.Admin;
      switch(role)
      {
        case Role.Admin:{Console.WriteLine("you're an admin."); break;}
        case Role.User:{Console.WriteLine("you're an user."); break;}
        case Role.Guest:{Console.WriteLine("you're an guest."); break;}
        default:{Console.WriteLine("deny to access."); break;}
      }
    }

    当然rust的match肯定不止于此,我们接着来看。


     二、match配合变体enum解构

    rust的变体enum可以包含不同数据类型,再加上match匹配可以轻松实现复杂的逻辑需求。
    我们还是来看个例子,比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    enum Operator{
      Plus(i32,i32),
      Subtract(i32,i32),
      Multiply(i32,i32),
      Divide(i32,i32),
      Log10(i32)
    }
     
    fn main(){
      let op=Operator::Plus(100,200);
      match op{
        Operator::Plus(a,b)=>println!("{a}+{b}={}",a+b),
        Operator::Subtract(a,b)=>println!("{a}-{b}={}",a-b),
        Operator::Multiply(a,b)=>println!("{a}x{b}={}",a*b),
        Operator::Divide(a,b)=>println!("{a}/{b}={}",a/b),
        Operator::Log10(a)=>println!("log10({a})={}",a.ilog10()),
      }
    }

    类似这样的需求还是比较多的,比如处理鼠标事件

    1
    2
    3
    4
    5
    6
    enum MouseEvent{
    MoveIn,
    MoveOut,
    Click(x,y),
    ...
    }

    像这个例子在面向对象的编程语言中,肯定是使用类型继承实现来到达目的,继承并非不好,而是组合才是更佳思维方式,就好比社会各种组织都是靠协作,而非强行大一统,每个部分都有自身最高效的运作方式,强行一致这样的组织也效率低下。


     三、复杂match匹配臂

    1、匹配区间模式

    1
    2
    3
    4
    5
    6
    7
    8
    fn main() {
        let num=100;
        match num{
            x @ 1 ..=3| x @ 6 ..=9=>println!("case 1.{x}"),
            4|5=>println!("case 2.b"),
            x=>println!("case 3.{x}")
        }
    }

      

    2、匹配通配符模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    fn main(){
        let test=vec!["b", "m", "r","x","n","t","f","j"];
        let s=(2,3,&test[0..3]);
        match s{
            (_,3,[..,"j"])=>println!("case 1."),
            (2,_,["rust",end @ ..])=>println!("case 2.{:?}",end),
            (_,_,_)=>println!("case 3."),
        }
    }

      

    当然还有一些其它的模式匹配就不一一说明了。


     四、用match消除if-else

      if-else是所有编程语言中最简单直接的逻辑流控制方式,以至于被滥用了,在加上变量命名随意,词不达意使得代码难以理解(最近自嘲的”防御式编程“例外),说实话三层if-else就足以让人琢磨,我曾见到过十几层的if-else,一个方法上千行,再后来曾几何时编程流行消除if-else,以C++,Java,C#等流行面向对象语言大多使用设计模式来消除if-else,以至于设计模式被滥用了。

    if-else并非是恶,既然提供了当用则用,无需顾虑太多。

    在rust中对于单个Option还是推荐用if let方式处理比较简单,比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    [Debug]
    struct User{
    user_name:String,
    age:u8
    }
    fn get_user(user_name:&str,pwd:&str)->Option{
      if user_name=="admin" && pwd=="123456"{
        Some(User{user_name,age:20})
      } else{
        None
      }
    }
     
    fn main(){
      let user=get_user("admin","123456");
      if let Some(user)=user{
        println!("login success {:?}",user);
      }
    }

      

    我们应该谨防的是一个函数大段代码多层if-else嵌套,这个就是坏味道了。在其它常用编程语言中可能我们会用if-else写出这样的代码,伪代码比如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    if user.phone!=null{
      if user.email!=null{
        send_message(user.phone);
        send_email(user.email);
        log("优质客户");
      }else{
        send_message(user.phone);
        log("普通客户");
      }
    }else{
      if user.email!=null{
        send_email(user.email);
        log("一般客户");
      }else{
        log("待发展客户");
      }
    }

      

    if-else是不是看得眼都花了,如果逻辑再复杂一些,这样的if-else嵌套更多层,人都麻了,不上个设计模式都有点不好意思了。
    我们来用rust的mach匹配看看如何消除使得代码更加清晰直观。伪代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    struct User{
    phone:Option,
    email:Option
    }
     
    fn main(){
      let user=User{phone:None,email:"bm@vv.com".to_owned()};
       
      match(user.phone,user.email){
        (Some(phone),Some(emial))=>{
          send_message(user.phone);
          send_email(user.email);
          log("优质客户");
        },
        (Some(phone),None)=>{
          send_message(user.phone);
          log("普通客户");
        },
        (None,Some(email))=>{
          send_email(user.email);
          log("一般客户");
        },
        (_,_)=>log("待发展客户")
      }
    }

      

    rust的match可以匹配多个目标,match使得层级单一了,整体逻辑是不是清晰多了。


     

    好了,啰嗦了这么多,感谢各位看官驻足在此停留。

    文章在博客园、微信公众号等平台发布,转载请注明来源(bmrxntfj)

  • 相关阅读:
    Spring Boot 2.x系列【23】应用监控篇之Info端点
    (免费领源码) python语言;django框架;mysql电子档管理系统28265-计算机毕业设计项目选题推荐
    javascript的AMD模式
    35-Jenkins-共享库应用
    Zookeeper集群 + Kafka集群
    基于STM32的循迹小车项目实战
    算法通关村第二关终于学会链表反转了
    Excel中的HLOOKUP、VLOOKUP、XLOOKUP函数
    Python之numpy
    java面试题-RabbitMQ面试题
  • 原文地址:https://www.cnblogs.com/bmrxntfj/p/rust_match.html