我在学习Rust时,注意到有4个概念经常放到一起讨论:Result、Option、unwapr和?操作符。本文记录了我对这4个Rust概念的思考,这个思考过程帮助我理解并学会了如何写出更地道的Rust代码。

区块链开发教程链接:以太坊 | 比特币 | EOS | Tendermint | Hyperledger Fabric | Omni/USDT | Ripple

1、Option - 可空变量

虽然Rust中有null的概念,但是使用null并不是Rust中常见的模式。假设我们要写一个函数,输入一种手机操作系统的名称,这个函数就会返回其应用商店的名称。如果传入字符串iOS,该函数将返回App Store;如果传入字符串android,那么该函数将返回Play Store。任何其他的输入都被视为无效。

在大多数开发语言中,我们可以选择返回null或字符串invalid来表示无效的结果,不过这不是Rust的用法。

地道的Rust代码应该让该函数返回一个Option。Option或更确切的说Option<T>是一个泛型,可以是Some<T>None(为了便于阅读,后续文章中将省略类型参数T)。Rust将SomeNone称为变体(Variant) —— 这一概念在其他语言中并不存在,因此我也不
去定义到底什么是变体了。

在我们的示例中,正常情况下函数将返回包裹在Some变体中的字符串常量App Store或Play Store。而在非正常情况下,函数将返回None。

fn find_store(mobile_os: &str) -> Option<&str> {match mobile_os {"iOS" => Some("App Store"),"android" => Some("Play Store"),_ => None}
}

要使用find_store(),我们可以用如下方式调用:

fn main() {println!("{}", match find_store("windows") {Some(s) => s,None => "Not a valid mobile OS"});
}

完整的代码如下:

fn find_store(mobile_os: &str) -> Option<&str> {match mobile_os {"iOS" => Some("App Store"),"android" => Some("Play Store"),_ => None}
}fn main() {println!("{}", match find_store("windows") {Some(s) => s,None => "Not a valid mobile OS"});
}

2、Result - 包含错误信息的结果

Result,或者更确切地说Result<T,E>,是和Rust中的Option相关的概念,它是一个加强版本的Option。

Result<T, E>可能有以下结果之一:

  • Ok(T):结果为成员T
  • Err(E):结果为故障成员E

与之前我们看到Option可以包含Some或None不同,Result中包含了错误相关信息,这是Option中所没有的。

让我们看一个函数实例,它返回一个Result。该函数摘自用于解析JSON字符串的serde_json库,其签名为:

pub fn from_str<'a, T>(s: &'a str) -> Result<T, Error>
whereT: Deserialize<'a>,

假设我们要解析如下的字符串:

let json_string = r#"{"name": "John Doe","age": 43,"phones": ["+44 1234567","+44 2345678"]}"#;

目标是解析为Rust的一个person结构对象:

#[derive(Serialize, Deserialize)]
struct Person {name: String,age: u8,phones: Vec<String>,
}

解析过程的Rust代码如下:

let p:Person = match serde_json::from_str(json_string) {Ok(p) => p,Err(e) => ... //we will discuss what goes here next
};

正常情况下可以得到期望的结果。不过假设在输入的json_string中有一个笔误,这导致程序运行时将执行Err分支。

当碰到Err时,我们可以采取两个动作:

  • panic!
  • 返回Err

3、unwrap - 故障时执行panic!

在上面的示例中,假设我们期望panic!:

let p: Person = match serde_json::from_str(data) {Ok(p) => p,Err(e) => panic!("cannot parse JSON {:?}, e"), //panic}

当碰到Err时,上面的代码panic!就会崩掉整个程序,也许这不是你期望的。我们可以修改为:

let p:Person = serde_json::from_str(data).unwrap();

如果我们可以确定输入的json_string始终会是可解析的,那么使用unwrap没有问题。但是如果会出现Err,那么程序就会崩溃,无法从故障中恢复。在开发过程中,当我们更关心程序的主流程时,unwrap也可以作为快速
原型使用。

因此unwrap隐含了panic!。虽然与更显式的版本没有差异,但是危险在于其隐含特性,因为有时这并不是你真正期望的行为。

无论如何,如果我们需要调用panic!,代码如下:

use serde::{Deserialize, Serialize};
use serde_json::Result;#[derive(Serialize, Deserialize)]
struct Person {name: String,age: u8,phones: Vec<String>,
}fn typed_example() -> Result<()> {//age2 is error on purposelet data = r#"{"name": "John Doe","age2": 43,"phones": ["+44 1234567","+44 2345678"]}"#;let p:Person = serde_json::from_str(data).unwrap();println!("Please call {} at the number {}", p.name, p.phones[0]);Ok(())
}fn main() {match typed_example() {Ok(_) => println!("program ran ok"),Err(_) => println!("program ran with error"),}
}

4、? - 故障时返回Err对象

当碰到Err时,我们不一定要panic!,也可以返回Err。不是每个Err都是不可恢复的,因此有时并不需要panic!。下面的代码返回Err:

let p: Person = match serde_json::from_str(data) {Ok(p) => p,Err(e) => return Err(e.into()),
};

?操作符提供了一个更简洁的方法来替换上面的代码:

let p:Person = serde_json::from_str(data)?;

这时完整的Rust程序代码如下:

use serde::{Deserialize, Serialize};
use serde_json::Result;#[derive(Serialize, Deserialize)]
struct Person {name: String,age: u8,phones: Vec<String>,
}fn typed_example() -> Result<()> {//age2 is error on purposelet data = r#"{"name": "John Doe","age2": 43,"phones": ["+44 1234567","+44 2345678"]}"#;let p: Person = serde_json::from_str(data)?;println!("Please call {} at the number {}", p.name, p.phones[0]);Ok(())
}fn main() {match typed_example() {Ok(_) => println!("program ran ok"),Err(e) => println!("program ran with error {:?}", e),}
}

5、使用unwrap和?解包Option

就像我们可以使用unwarp和?来处理Result,我们也可以使用unwrap和?来处理Option。

如果我们unwrap的Option的值是None,那么程序就会panic!。示例如下:

fn next_birthday(current_age: Option<u8>) -> Option<String> {// If `current_age` is `None`, this returns `None`.// If `current_age` is `Some`, the inner `u8` gets assigned to `next_age` after 1 is added to itlet next_age: u8 = current_age?;Some(format!("Next year I will be {}", next_age + 1))
}fn main() {let s = next_birthday(None);match s {Some(a) => println!("{:#?}", a),None => println!("No next birthday")}
}

原文链接:Rust学习 - Result/Option/unwrap/? — 汇智网

理解Rust中的Result/Option/unwrap/?相关推荐

  1. Rust学习 - Result/Option/unwrap/?

    学习Rust时,注意到有4个概念经常放到一起讨论:Result.Option.unwapr和?操作符. 本文记录了我对这4个Rust概念的思考,这个思考过程帮助我理解并学会了如何写出更地道的Rust代 ...

  2. i3够晚rust吗_【译】理解Rust中的Futures (一)

    原文标题:Understanding Futures In Rust -- Part 1 原文链接:https://www.viget.com/articles/understanding-futur ...

  3. Rust中的关键字Some、Option

    文章目录 Rust中的关键字Some.Option 关于枚举 Option Some使用举例 参考 Rust中的关键字Some.Option 根据Rust本身的设计哲学, 建议在设计某个变量时, 如果 ...

  4. 17.Rust中函数式语言功能:迭代器与闭包

    Rust 的设计灵感来源于很多现存的语言和技术.其中一个显著的影响就是 函数式编程(functional programming).函数式编程风格通常包含将函数作为参数值或其他函数的返回值.将函数赋值 ...

  5. 【Rust日报】2020-01-27 QIP:Rust中的量子计算模拟

    QIP:Rust中的量子计算模拟 量子计算库利用图形构建来构建有效的量子电路仿真.对于借口模型的量子计算,Rust是一种很棒的语言,因为借位检查器与无克隆定理非常相似. 请参阅Github仓库的exa ...

  6. 【转】Android菜单详解——理解android中的Menu--不错

    原文网址:http://www.cnblogs.com/qingblog/archive/2012/06/08/2541709.html 前言 今天看了pro android 3中menu这一章,对A ...

  7. Android菜单详解——理解android中的Menu

    前言 今天看了pro android 3中menu这一章,对Android的整个menu体系有了进一步的了解,故整理下笔记与大家分享. PS:强烈推荐<Pro Android 3>,是我至 ...

  8. rust 案例_理解Rust的引用与借用

    困惑 接触Rust也一段时间了,但对References(引用) .borrowing(借用) . &关键字.ref关键字.* 关键字,这几个词非常困惑.常见的问题不在乎下面几条: & ...

  9. java中demo接人_return的用法_如何理解java中return的用法?

    C语言中return用法?(请熟练者进) return是返回值,这个返回值是和函数的类型有关的,函数的类型是什么,他的返回值就是什么 比方主函数intmain() {}这里就必须有一个return,只 ...

最新文章

  1. Gym 101845(2018 ACM-ICPC, Universidad Nacional de Colombia Programming Contest)
  2. Android小知识-电量优化WakeLock的使用
  3. spring用xml还是java_Spring中如何混用XML与Java装配方式
  4. 北京2019高考分数线:本科理423文480
  5. Crawl:利用bs4和requests爬取了国内顶级某房源平台(2020年7月2日上海二手房)将近30*100多条数据并进行房价分析以及预测
  6. 机器学习实战_09_树回归_源代码错误修正
  7. Redis源码剖析(六)事务模块
  8. android: 静态XML和动态加载XML混合使用,以及重写Layout控件
  9. 解决win7下nodejs安装运行报错:Node.js is only supported on Windows 8.1, Windows Server 2012 R2... 之不支持高版本问题
  10. 一个商城的购车相关代码
  11. 还没吃透内存缓存LruCache实现原理的看这篇文章,面试必会
  12. OC 中NSString与NSString 的比较
  13. 细菌基因组基本概念(一)
  14. c++中double类型控制小数位数
  15. 说一下你对多态的理解?_如何去理解java中的多态?从jvm角度分析也许让你更清晰...
  16. Tukey‘s test方法 异常值
  17. linux下nfs安装配置
  18. 大专计算机考试题,大专计算机考试试题.doc
  19. c语言可编写的游戏,占卜子女兴盛大全篇
  20. win10部署milvus以图搜图2.0

热门文章

  1. 动力节点—2020最新MyBatis教程笔记
  2. 让机器人依靠视觉识别抓取特定物体
  3. 记录解决cmd打不开/闪退
  4. 苹果mp3软件_一款非常不错的音频格式转换软件
  5. MATLAB多普勒哈伦分析
  6. jQuery方法返回jQuery对象还是DOM对象
  7. 27m3氨基酸发酵反应釜设计
  8. Oracle字节、字符的截取
  9. 增量pi和pid调节代码
  10. IBM 国际商业机器公司