【Rust】罗列和模式匹配——Rust语言基础14

打印 上一主题 下一主题

主题 978|帖子 978|积分 2934

1. 罗列类型

罗列(enumerations),也被称作 enums。罗列答应你通过罗列可能的成员(variants)来定义一个类型。首先,我们会定义并使用一个罗列来展示它是怎样连同数据一起编码信息的。罗列类型可以看作是一个类型的集合。
例如下面这样定义一个罗列:
  1. enum Lunch {
  2.         duck,
  3.         rabbit,
  4.         chicken,
  5. };
复制代码
对没错,上面的例子展示了一个经典的鸡兔同笼的场景。
   问题:笼子里有3只鸡,6只鸭子,5只兔子,请问为什么有37只脚?
答:因为有一只鸡在独立。
    问题:笼子里有3只鸡,6只鸭子,5只兔子,请问为什么有36只脚?
答:因为有两只鸡在独立!
答复错误!!
正确答复:因为有一只鸡在睡觉没看到脚。
  好了,开个玩笑,定义一个罗列变量就像上面一样简单。
如下便是使用罗列变量的示例:
  1.         let goku = Lunck::chichen;
  2.         let kuririn = Lunck::duck;
复制代码
相信有其他编程语言基础的同砚对此肯定不会生疏,不过更风趣的是,在 rust 中的罗列变量的成员几乎可以指定为任何类型,就像下面这样使用。
  1.     enum IpAddr {
  2.         V4(u8, u8, u8, u8),
  3.         V6(String),
  4.     }
  5.     let home = IpAddr::V4(127, 0, 0, 1);
  6.     let loopback = IpAddr::V6(String::from("::1"));
复制代码
亦大概是这样。
  1. enum Message {
  2.     Quit,
  3.     Move { x: i32, y: i32 },
  4.     Write(String),
  5.     ChangeColor(i32, i32, i32),
  6. }
复制代码
这些类型的指定都是被 rust 所答应的。请告诉我你们没有忘记这些类型代表什么意义吧~,好吧忘了也没关系,再来复习一次:


  • Quit 没有关联任何数据。
  • Move 类似结构体包罗命名字段。
  • Write 包罗单独一个 String。
  • ChangeColor 包罗三个 i32。
上面的罗列类型等同于多个结构体类型的定义:
  1. struct QuitMessage; // 类单元结构体
  2. struct MoveMessage {
  3.     x: i32,
  4.     y: i32,
  5. }
  6. struct WriteMessage(String); // 元组结构体
  7. struct ChangeColorMessage(i32, i32, i32); // 元组结构体
复制代码
这样看罗列在肯定程度上是会比结构体要方便多了,而且罗列变量同样可以通过 impl 块来定义属于该罗列的方法:
  1.     impl Message {
  2.         fn call(&self) {
  3.             // 在这里定义方法体
  4.         }
  5.     }
  6.     let m = Message::Write(String::from("hello"));
  7.     m.call();
复制代码
1.2. Option 罗列

Option 也是一个罗列类型,在 rust 中没有空值 Null 的概念,由于考虑到所有变量都存在一种空值和非空值的状态会为编程语言带了巨大问题甚至是会引起各种漏洞,因此 rust 摒弃了这一设计理念,但由于空值同时也具有特别意义,又会为编程带来很多便利,取而代之则衍生出 Option 这样的罗列。
在 rust 标准库中是这样定义的:
  1. enum Option<T> {
  2.     None,
  3.     Some(T),
  4. }
复制代码
这里的 <T> 语法是一个泛型参数,虽然目前还没学习到,但相信各人也不生疏,泛型在其它编程语言中也是很常见和紧张的存在。这里的 None 就表示没有值,肯定程度上等价于 Null 的作用。
2. match 控制流结构

Rust 有一个叫做 match 的极为强大的控制流运算符,它答应我们将一个值与一系列的模式相比较,并根据相匹配的模式执行相应代码。模式可由字面值、变量、通配符和许多其他内容构成;。match 的力气泉源于模式的表现力以及编译器查抄,它确保了所有可能的情况都得到处置惩罚。
假设有这样一个场景,如今要上海陆家嘴举行 2025 年天下第一武道大会,邀请了:


  • 埼玉《一拳超人》
  • 五条悟《咒术回战》
  • 孙悟空《七龙珠》
  • 漩涡鸣人《火影忍者》
  • 贝吉塔《七龙珠》
  • 蒙奇·D·路飞《海贼王》
这些著名高手来到场,如今要根据这些选手的战斗本领为他们做排名。
  1. enum Hero {
  2.     Saitama,
  3.     Satoru,
  4.     Goku,
  5.     Naruto,
  6.     Bejita,
  7.     Ruffy,
  8. }
  9. fn rank(hero: Hero) -> u8 {
  10.         match hero {
  11.                 Hero:Saitama => 1,
  12.                 Hero:Satoru=> 2,
  13.                 Hero:Goku=> 3,
  14.                 Hero:Naruto=> 4,
  15.                 Hero:Bejita=> 5,
  16.                 Hero:Ruffy=> 6,
  17.         }
  18. }
复制代码
[注]:这里主持人给的排名仅作为参考,并不具备实际意义,请根据各人本身内心估值来判定。也不要问为什么没有请某某某来,上海市举行方表示资金有限,请不起所有高手聚集此地。
好了,根据上面的简单例子相信各位也可以或许对 match 的功能相识一二,这里就有人站出来说了“这?这不就是 switch & case 语句嘛~”,欸,差不多,但是 rust 的 match 要更加强大一点,请继续往下看。
2.1. match 对绑定值的匹配

正如上文提到,罗列变量可以为其成员指定几乎任何类型,对这种情况 match 该怎样应对?
  1. enum Hero {
  2.     Saitama(i32),
  3.     Satoru(i32),
  4.     Goku(i32),
  5.     Naruto(i32),
  6.     Bejita(i32),
  7.     Ruffy(i32),
  8. }
  9. // 整数表示其战斗力数值
  10. fn power(hero: Hero) {
  11.         match hero {
  12.                 Hero::Saitama(p) => {
  13.                         println!("埼玉: {}", p);
  14.                 },
  15.                 Hero::Satoru(p) => {
  16.                         println!("五条: {}", p);
  17.                 },
  18.                 Hero::Goku(p) => {
  19.                         println!("悟空: {}", p);
  20.                 },
  21.                 Hero::Naruto(p) => {
  22.                         println!("鸣人: {}", p);
  23.                 },
  24.                 Hero::Bejita(p) => {
  25.                         println!("王子: {}", p);
  26.                 },
  27.                 Hero::Ruffy(p) => {
  28.                         println!("草帽小子: {}", p);
  29.                 },
  30.         }
  31. }
  32. fn main() {
  33.     let goku = Hero::Goku(12000);
  34.     power(&goku);
  35. }
复制代码
rust 中答应这样的匹配,正如上述例子中,将会匹配到 goku 属于 Hero::Goku(p) 类型,并同时将其值绑定到了 p 变量,这样就可以获取其战斗力数值了。
2.2. Option 的匹配

比如我们想要编写一个函数,它获取一个 Option<i32> ,如果其中含有一个值,将其加一。如果其中没有值,函数应该返回 None 值,而不尝试执行任何操纵。
得益于 match,编写这个函数非常简单:
  1.     fn plus_one(x: Option<i32>) -> Option<i32> {
  2.         match x {
  3.             None => None,
  4.             Some(i) => Some(i + 1),
  5.         }
  6.     }
  7.     let five = Some(5);
  8.     let six = plus_one(five);
  9.     let none = plus_one(None);
复制代码
让我们更细致地查抄 plus_one 的第一行操纵。当调用 plus_one(five) 时,plus_one 函数体中的 x 将会是值 Some(5)。接着将其与每个分支比较。
  1.             None => None,
复制代码
值 Some(5) 并不匹配模式 None,所以继续进行下一个分支。
  1.             Some(i) => Some(i + 1),
复制代码
Some(5) 与 Some(i) 匹配吗?固然匹配!它们是雷同的成员。i 绑定了 Some 中包罗的值,所以 i 的值是 5。接着匹配分支的代码被执行,所以我们将 i 的值加一并返回一个含有值 6 的新 Some。
需要注意的一点是,match 匹配是穷举匹配,必须要为所有可能的效果编写对应的匹配处置惩罚过程,否则编译器将会制止这种情况。
2.3. 通配模式以及 _ 占位符

将上面的代码做以简单改动:
  1. enum Hero {
  2.     Saitama(i32),
  3.     Satoru(i32),
  4.     Goku(i32),
  5.     Naruto(i32),
  6.     Bejita(i32),
  7.     Ruffy(i32),
  8. }
  9. // 整数表示其战斗力数值
  10. fn power(hero: Hero) {
  11.         match hero {
  12.                 Hero::Saitama(p) => {
  13.                         println!("埼玉: {}", p);
  14.                 },
  15.                 Hero::Satoru(p) => {
  16.                         println!("五条: {}", p);
  17.                 },
  18.                 other => {
  19.                 // _ => {        // 与上一行代码等价
  20.                         println!("战斗能力未知!!!");
  21.                 },
  22.         }
  23. }
  24. fn main() {
  25.     let goku = Hero::Goku(12000);
  26.     power(&goku);
  27. }
复制代码
最后一个分支则涵盖了所有其他可能的值,模式是我们命名为 other 的一个变量。
3. if let 控制流

这个语法很像 C/C++ 中的 if 语句,因此掌握起来也非常容易,还是照例给个例子看的比较直白一些:
  1. enum Hero {
  2.     Saitama(i32),
  3.     Satoru(i32),
  4.     Goku(i32),
  5.     Naruto(i32),
  6.     Bejita(i32),
  7.     Ruffy(i32),
  8. }
  9. fn main() {
  10.     let goku = Hero::Goku(12000);
  11.     //power(&goku);
  12.     //
  13.     if let Hero::Goku(p) = goku {
  14.         println!("悟空: {}", p);
  15.     } else {
  16.         println!("战斗能力未知!!!");
  17.     }
  18.    
  19. }
复制代码
相信这样简单的例子各人一看便可以或许明了,当 if let 的条件建立将会进入下方代码块,否则不会,就是这样简单的语句。
4. 小测试

这样以来,条件控制语句我们也掌握的差不多了,看完了,也懂了,让我们试着用一下吧。
接下来我们要实现一个这样的场景,接着上面天下第一武道大会竣事之后,还是这些参赛选手们听闻孙悟空会一个绝技“融合”!每个人都很感爱好,都希望试试本身与另外一个人融合之后会产生什么样的征象。
假设融合对象只能是如下:


  • 五条悟 & 漩涡鸣人
  • 埼玉 & 路飞
  • 孙悟空 & 贝吉塔
  • 其它情况则融合失败。
  1. impl Hero {
  2.     fn fusion(&self, other: &Hero) -> Hero {
  3.         match self {
  4.             Hero::Saitama(p) | Hero::Ruffy(p) => {
  5.                 Hero::Saiffy(self.get() + other.get(), String::from("saitama&ruffy"))
  6.             },
  7.             Hero::Satoru(p) | Hero::Naruto(p) => {
  8.                 Hero::Natoru(self.get() + other.get(), String::from("satoru&naruto"))
  9.             },
  10.             Hero::Goku(p) | Hero::Bejita(p) => {
  11.                 Hero::Gojita(self.get() + other.get(), String::from("goku&bejita"))
  12.             },
  13.             other => {
  14.                     println!("融合失败!!!");
  15.                 Hero::NULL
  16.             },
  17.         }
  18.     }
  19.     fn get(&self) -> &i32 {
  20.         match self {
  21.             Hero::Saitama(p) => p,
  22.             Hero::Satoru(p) => p,
  23.             Hero::Goku(p) => p,
  24.             Hero::Naruto(p) => p,
  25.             Hero::Bejita(p) => p,
  26.             Hero::Ruffy(p) => p,
  27.             other => &0,
  28.         }
  29.     }
  30. }
  31. #[derive(Debug)]
  32. enum Hero {
  33.     Saitama(i32),
  34.     Satoru(i32),
  35.     Goku(i32),
  36.     Naruto(i32),
  37.     Bejita(i32),
  38.     Ruffy(i32),
  39.     NULL,
  40.     Gojita(i32, String),
  41.     Natoru(i32, String),
  42.     Saiffy(i32, String),
  43. }
  44. fn main() {
  45.     let goku = Hero::Goku(12000);
  46.     let bejita = Hero::Bejita(16000);
  47.     let gojita = Hero::fusion(&goku, &bejita);
  48.     println!("goku+bejita = {:?}", gojita);
  49. }
复制代码
[注]:上面代码仅供读者参考,希望各人可以或许实现出更加风趣的代码~
下一篇《Rust语言基础15》

   以为这篇文章对你有帮助的话,就留下一个赞吧v*
请尊重作者,转载还请注明出处!感谢配合~
[作者]: Imagine Miracle
[版权]: 本作品接纳知识共享署名-非商业性-雷同方式共享 4.0 国际许可协议进行许可。
[本文链接]: https://blog.csdn.net/qq_36393978/article/details/146249359

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

使用道具 举报

0 个回复

正序浏览

快速回复

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

本版积分规则

天空闲话

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表