通过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<T>还是推荐用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<User>{
  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<String>,
email:Option<String>
}
 
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)

posted @ 2023-12-14 15:33 bmrxntfj 阅读(291) 评论(0) 推荐(1) 编辑

聊一聊Rust的enum

摘要: enum在实际编程中是非常常用的,从enum来看rust,跟其它语言的enum相比,rust的enum更能适应未来编程需求。 阅读全文
posted @ 2023-12-13 14:03 bmrxntfj 阅读(587) 评论(0) 推荐(1) 编辑

折旧记录某旅纵横app分析研究

摘要: 首先申明,这是三年前的事情,当时为了学习研究,未做任何破坏行为,仅在次记录下。现在很多公司对app安全都非常重视,研究难度越来越大,早前app大多裸奔,随手就能看到java代码,即使通讯加密也都是java层的,一顿分析就能学习到想要的数据。而今各种加壳,反调试,native code等,还有些我不知道的,要学习到数据都要一关一关过。当时用到的一些工具和分析方法,也都是大家熟悉的IDA、Frida、Cydia、Xposed等。 阅读全文
posted @ 2022-03-05 17:20 bmrxntfj 阅读(594) 评论(0) 推荐(0) 编辑

实现自己的js框架

摘要: 很早之前一直用extjs,这个确实非常强大,但是在IE下一直都有一个性能的问题,搞得要让客户换chrome,firefox浏览器才行。 之所以要写自己js框架,原因是觉得自己实现也简单,维护也方便。 可能你要问为什么不用jquery插件,一样可以。但是这些插件代码质量不能保证,风格也是奇形怪状,出了问题还要去看代码,改了之后又跟原作者的有出入,以后同步更加麻烦。 不用jquery插件,但是jquery却是个好东西,解决了浏览器兼容的大问题,所以我这个就是基于jquery来实现的,因为一直喜欢extjs的代码风格,所以如果你使用过extjs的话,使用起来会轻车熟路。 阅读全文
posted @ 2013-11-22 08:46 bmrxntfj 阅读(4406) 评论(11) 推荐(8) 编辑

实现自己的Linq to Sql

摘要: 之前写过一篇《统一的仓储接口》,为了方便使用不同的仓储。在我们的项目中使用的是EF4.0,但是这个版本的EF有一些性能问题没有解决,又不想升级到EF6,具体EF6有没有解决暂时不清楚。我们的项目之前运行的都不错,突然一天数据库服务器CPU 100%,IIS服务器CPU又正常,过几个小时之后又恢复正常,每个星期一早上都这样,可以肯定就是用户同时操作并发过多造成,查找之后,是一个表的数据被锁住。报错was deadlocked on lock,解决办法就是查询sql上加上 with nolock,但是EF不支持,但有不想放弃linq to sql的优势,无奈只能自己实现,方案是之前已有功能并发不多的地方保持不变,依然使用EF,在并发多的地方使用自己实现的linq to sql。 阅读全文
posted @ 2013-11-21 10:45 bmrxntfj 阅读(1727) 评论(3) 推荐(4) 编辑

统一的仓储接口

摘要: 目前,各种数据访问组件多如牦牛,提供接口各不相同,虽然大多都支持不同数据存储,但是还是存在一些问题, 有的团队成员喜欢用EF,有的喜欢用NHibernate,口味难调。于是我希望能有一组标准的接口,这样可以统一 代码的,也可以满足各成员的喜好。 阅读全文
posted @ 2011-11-09 14:25 bmrxntfj 阅读(1908) 评论(1) 推荐(0) 编辑

ddd官方终于发布了一个完整的示例

摘要: 例子就是ddd书中第7章讲的货物运输 阅读全文
posted @ 2009-04-23 11:06 bmrxntfj 阅读(1852) 评论(2) 推荐(0) 编辑

浅谈值对象

摘要: 值对象既然需要提供全局查询,那么这个职责有谁来承担? 阅读全文
posted @ 2009-03-18 10:32 bmrxntfj 阅读(1248) 评论(0) 推荐(0) 编辑

分层随想

摘要: 关于层的一点理解 阅读全文
posted @ 2008-11-11 15:38 bmrxntfj 阅读(476) 评论(2) 推荐(0) 编辑

prototype模式随想

摘要: 成功的经验值得总结,然而失败的经验更值得总结。 阅读全文
posted @ 2008-08-01 12:00 bmrxntfj 阅读(394) 评论(1) 推荐(0) 编辑

ddd心得

摘要: 学习实践ddd过程中的一点点心得 阅读全文
posted @ 2008-07-09 17:33 bmrxntfj 阅读(1164) 评论(0) 推荐(0) 编辑

ddd分层感想

摘要: 因为分层的原则,所有设计的依赖就必须是单向的,如果下层要调用上层的对象,问题就出现了。 在ddd书中也提到了,使用回调或Observer模式可以解决。 如果不使用MVC,在infrastructure 和Domain之间也许只能提供Meta Mapping Layer才能解决问题。 阅读全文
posted @ 2008-07-08 10:39 bmrxntfj 阅读(1802) 评论(2) 推荐(0) 编辑

小boss随想

摘要: boss总抱怨员工跳槽,员工不安分守己。 阅读全文
posted @ 2008-07-01 10:35 bmrxntfj 阅读(702) 评论(6) 推荐(0) 编辑

论软件的价值

摘要: 衡量软件的价值是由客户所获得的利益决定的。因此我们要根据客户所获得的利益跟客户要钱。 阅读全文
posted @ 2008-06-30 13:14 bmrxntfj 阅读(2340) 评论(16) 推荐(0) 编辑

Composite模式随想

摘要: composite应用中的问题 阅读全文
posted @ 2008-06-16 13:22 bmrxntfj 阅读(500) 评论(0) 推荐(0) 编辑

DDD书籍介绍

摘要: NET Domain-Driven Design with C# 作者:Tim McCarthyblog:http://blogs.interknowlogy.com/timmccarthy/archive/2007/04/26/13024.aspx另外作者在codeplex上有一个开源的ddd项目。非常值得一看。中文版应该还没有http://www.codeplex.com/dddpds他的bl... 阅读全文
posted @ 2008-06-05 16:15 bmrxntfj 阅读(1257) 评论(2) 推荐(0) 编辑

Bmrxntfj.UIMapper界面对象映射

摘要: (UIMapper)界面/对象映射 主要是为了隔离界面,把重心放在领域模型上。在领域模型中,一切皆为对象。 比如O/RM,也是为了隔离关系数据到领域对象的转换。 阅读全文
posted @ 2008-04-19 14:57 bmrxntfj 阅读(634) 评论(1) 推荐(0) 编辑

闲来没事,写个老玩意

摘要: 再写DataAsscess 阅读全文
posted @ 2008-03-09 02:25 bmrxntfj 阅读(296) 评论(0) 推荐(0) 编辑

Strategy与Template Method

摘要: Strategy与Template Method 阅读全文
posted @ 2008-02-27 16:38 bmrxntfj 阅读(381) 评论(0) 推荐(0) 编辑

规格模式(Specification)

摘要: 规格模式(Specification) 阅读全文
posted @ 2008-02-17 18:20 bmrxntfj 阅读(2364) 评论(2) 推荐(1) 编辑
< 2025年3月 >
23 24 25 26 27 28 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 26 27 28 29
30 31 1 2 3 4 5

统计

点击右上角即可分享
微信分享提示