在上一节中,我们研究了IpAddr枚举如何使我们使用Rust的类型系统对更多信息进行编码,而不仅仅是将数据编码到程序中。本节探讨的案例研究Option,这是标准库定义的另一个枚举。Option类型在很多地方都使用,因为它对非常常见的情况进行编码,在这种情况下,值可以是某些值,也可以是任何值。用类型系统来表达这个概念意味着编译器可以检查您是否已经处理了所有您应该处理的情况。此功能可以防止其他编程语言中极为常见的错误。

通常会根据所包含的功能来考虑编程语言设计,但是所排除的功能也很重要。Rust没有许多其他语言具有的null功能。Null是一个值,表示那里没有任何值。在具有null的语言中,变量始终可以处于以下两种状态之一:null或非null。

null的发明者Tony Hoare在2009年的演讲“ Null References:十亿美元的错误”中说:

我称之为我的十亿美元错误。当时,我正在设计第一个全面的类型系统,以面向对象的语言进行引用。我的目标是确保所有对引用的使用都绝对安全,并由编译器自动执行检查。但是我无法抗拒引入空引用的诱惑,仅仅是因为它是如此容易实现。这导致了无数错误,漏洞和系统崩溃,在最近四十年中可能造成十亿美元的痛苦和破坏。

空值的问题在于,如果您尝试将空值用作非空值,则会出现某种错误。由于此null或not-null属性无处不在,因此很容易产生这种错误。

但是,null试图表达的概念仍然是一个有用的概念:null是当前由于某种原因而无效或不存在的值。

问题不在于概念,而在于特定的实现。这样,Rust没有空值,但是它确实有一个枚举,该枚举可以编码存在或不存在的值的概念。该枚举是 Option,由标准库 定义如下:

enum Option {    Some(T),    None,}

Option枚举是非常有用,它甚至包括中拉开序幕; 您无需将其明确纳入范围。此外,这样是它的变体:你可以使用Some和None直接不带Option::前缀。该 Option枚举仍然只是一个普通的枚举,并Some(T)和None类型仍然变种Option。

语法是,我们还没有谈到尚Rust的特点。这是一个泛型类型参数,我们将在第10章中更详细地介绍泛型。现在,您只需要知道,这意味着枚举的Some变体 Option可以容纳任何类型的数据。以下是一些使用Option值保存数字类型和字符串类型的示例:

    let some_number = Some(5);    let some_string = Some("a string");    let absent_number: Option = None;

如果使用None而不是Some,则需要告诉RustOption我们拥有哪种类型 ,因为编译器无法Some 通过仅查看一个None值来推断该变量将拥有的类型。

当我们拥有一个Some值时,我们知道存在一个值并将该值保存在内Some。None从某种意义上说,当我们拥有一个值时,它与null含义相同:我们没有一个有效的值。那么,为什么有 Option比没有更好呢?

简而言之,因为Option和T(T可以是任何类型)是不同的类型,所以编译器不会让我们使用Option值,就好像它绝对是有效值一样。例如,此代码不会编译,因为它正在尝试向中添加i8一个Option:

    let x: i8 = 5;    let y: Option = Some(5);    let sum = x + y;

如果运行此代码,则会收到如下错误消息:

$ cargo run   Compiling enums v0.1.0 (file:///projects/enums)error[E0277]: cannot add `std::option::Option` to `i8` --> src/main.rs:5:17  |5 |     let sum = x + y;  |                 ^ no implementation for `i8 + std::option::Option`  |  = help: the trait `std::ops::Add<:option::option>>` is not implemented for `i8`error: aborting due to previous errorFor more information about this error, try `rustc --explain E0277`.error: could not compile `enums`.To learn more, run the command again with --verbose.

激烈!实际上,此错误消息表示Rust不了解如何添加i8和Option,因为它们是不同的类型。当我们具有i8Rust中类似类型的值时,编译器将确保我们始终具有有效值。我们可以放心地进行操作,而不必在使用该值之前检查null。只有当我们有一个Option(或我们正在使用的任何类型的值)时,我们才需要担心可能没有值,并且编译器将确保我们在使用该值之前处理该情况。

换句话说,您必须先将转换为Option,T然后才能对其执行T操作。通常,这有助于捕获null最常见的问题之一:假设某事物实际上并非为null。

不必担心会错误地假设一个非空值,这有助于您对代码更有信心。为了拥有一个可能为null的值,您必须通过设置value的类型来明确选择加入Option。然后,当您使用该值时,要求您显式处理该值为null的情况。每个值的类型都不是 Option,您可以放心地假设该值不为null。对于Rust来说,这是一个故意的设计决策,旨在限制null的普遍性并提高Rust代码的安全性。

那么,当您拥有类型的值以便可以使用该值时,如何T从Some变量中获取Option值呢?该Option枚举具有大量的是在各种情况下有用的方法; 您可以在文档中查看它们。Option在使用Rust的过程中,熟悉其中的方法将非常有用。

通常,为了使用Option值,您需要具有可处理每个变量的代码。您需要一些仅在具有Some(T)值时才运行的代码 ,并且允许该代码使用inner T。如果您有一个None值,那么您希望其他一些代码运行,而该代码没有T 可用的值。该match表达式是一个控制流构造,与枚举一起使用时会执行此操作:它将运行不同的代码,具体取决于它具有的枚举的变体形式,并且该代码可以使用匹配值内的数据。

这里的None就是和空值表达类似的东西。那为什么要使用None而不是空值呢?这里有一个很重要的一点,Option和T不是同一个类型。不要小看着一个简单的区别,这意味着Option和T是不能直接进行运算的,即Option和i32是不能直接相加的。实际上,更进一步的,在对Option进行T的运算时,必须先将Option转化成T类型。如此一来就可以帮助我们避免以为值非空而实际为空的情况。例如下面这段代码:

fn main() {    let a: i32 = 1;    let b: Option = Some(5);    let c = a + b;    println!("{}", c);}

编译器会报如下错误

error[E0277]: cannot add `std::option::Option` to `i32` --> src/main.rs:4:15  |4 |     let c = a + b;  |               ^ no implementation for `i32 + std::option::Option`  |  = help: the trait `std::ops::Add<:option::option>>` is not implementedfor `i32`error: aborting due to previous error

我们必须先将b从Option类型转化为i32才能进行i32类型的运算。如下

fn main() {    let a: i32 = 1;    let b: Option = Some(5);    let c = a + b.unwrap();    println!("{}", c);}

另外,每当我们引入一个可能为空的值时,我们必须先把它放到Option里。当我们使用这个值时,我们必须先处理值为空的情况。也就是说,只要一个值不是Option类型的,我们就可以认定它的值不为空。

这个设计相当有意思,我又查了一些资料发现scala里就存在这个设计,rust应该就是借鉴的scala的做法,无怪乎有人说rust参考了c/c++和haskell/scala两类语言。如果有机会应该多见识一下其他的语言,开阔下思路(虽然工作估计还是c/c++,(-_-||)

rust 案例_Rust特殊枚举Option用法相关推荐

  1. Rust 学习3, 枚举,集合

    Option枚举 Option定义于标准库中,并且会与导入(我们不需要主动引入), 描述了某个值可能存在(某种类型)或不存在的情况 // 4月16日每日一题 //给定一个整数 n ,返回 可表示为两个 ...

  2. boost::histogram::axis::option用法的测试程序

    boost::histogram::axis::option用法的测试程序 实现功能 C++实现代码 实现功能 boost::histogram::axis::option用法的测试程序 C++实现代 ...

  3. C# 枚举高级用法之Description

    c# 枚举高级用法之 基础枚举 namespace TestEnum {//声明public enum Name{//默认值 boob = 0 ,依次往下排,可自定义 jackMa = 3,jackC ...

  4. enum枚举类型用法

    文章目录 1. 枚举类型和枚举变量 1.1 枚举类型的定义和声明 1.2 枚举变量的定义和声明 2. 枚举变量和枚举常量的关联对应 3. 枚举类型和变量的应用 3.1 作为判断语句中的逻辑 3.2 一 ...

  5. rust 案例_Option 和 unwrap

    上个例子展示了如何主动地引入程序失败(program failure).当公主收到蛇这件不合适 的礼物时,我们就让程序 panic.但是,如果公主期待收到礼物,却没收到呢?这同样 是一件糟糕的事情,所 ...

  6. rust原地复活_Rust语言的缺点

    经常看到Rust吹,好像一门语言能解决所有的问题,但事实上并不是这样.就好像刚开始对Haskell感兴趣是在网上看到Haskell简洁优雅的快排,但是传教士不会告诉你这不是原地排序,时间复杂度也有很大 ...

  7. 枚举类型用法_Mybatis-plus常见用法总结三

    前面已经介绍了Mybatis-plus基本用法,今天为大家分享一些Mybatis-plus高级应用 逻辑删除 自动注入 枚举类型处理 Sql注入器 多租户 表结构 CREATE TABLE `sys_ ...

  8. Java enum(枚举)的用法详解(转)

    用法一:常量 在JDK1.5 之前,我们定义常量都是: public static fianl.... .现在好了,有了枚举,可以把相关的常量分组到一个枚举类型里,而且枚举提供了比常量更多的方法. p ...

  9. 详解C# 枚举高级用法之Description

    基础枚举 namespace TestEnum {//声明public enum Name{//默认值 boob = 0 ,依次往下排,可自定义 jackMa = 3,jackCHan那就= 4boo ...

最新文章

  1. 关于 JS 模块化的最佳实践总结
  2. Thread pool引起的程序连接数据库响应慢
  3. 12.14-Linux系统优化
  4. EBS MOAC深入研究(转)
  5. MongoDB Aggregation聚合操作
  6. 脱库数据分享论坛_22G疑为12306脱库文件大揭秘
  7. 如何将google切片发布成arcgis服务并生成tpk包
  8. 计算机专业网页设计周志,毕业设计周志范文100篇
  9. Java生成随机数的方法
  10. html渐变做一个彩虹,ps渐变工具:制作七色彩虹特效
  11. bzoj 4816: [Sdoi2017]数字表格 莫比乌斯反演
  12. 恒指赵鑫:7.24今日恒指喊单记录与小结
  13. 考研词汇 用语言记忆
  14. AD学习笔记(一)基础认识
  15. 多模态分析数据集(Multimodal Dataset)整理
  16. CentOS系统磁盘目录空间调整
  17. 最火热的季节,却承载着最盛大的离别
  18. 什么是威胁情报(Threat Intelligence)
  19. 树莓派微型计算机教程,一步即达——Lakka傻瓜教程
  20. 奇数位于偶数之前:调整数组顺序使得奇数位于偶数之前。调整之后,不关心大小顺序。 如数组:[1,2,3,4,5,6] 调整后可能是:[1, 5, 3, 4, 2, 6]

热门文章

  1. jmeter导入DB数据再再优化
  2. ubuntu 下LAMP服务器环境搭建
  3. Flutter 弧度与角度之间的换算
  4. Android-获取系统的应用程序的信息
  5. java基础—System类的方法演示
  6. 如何在文件夹中创建nodeJs项目
  7. Mr.J---重拾Ajax(一)--XMLHttpRequest
  8. 开源项目之kisso
  9. TortoiseGit 分支管理策略
  10. LeetCode——maximal-rectangle