当前位置: 首页 > news >正文

【Rust自学】9.2. Result枚举与可恢复的错误 Pt.1:match、expect和unwrap处理错误

喜欢的话别忘了点赞、收藏加关注哦,对接下来的教程有兴趣的可以关注专栏。谢谢喵!(=・ω・=)

9.2.1. Result枚举

通常情况下,错误都没有严重到需要停止整个程序的地步。某个函数之所以运行失败或者是遇到错误通常是由一些可以简单解释并做出响应的原因引起的。比如说程序要打开某个文件,但是这个文件并不存在,这个时候通常会考虑创建这个文件而不是直接终止程序。

Rust提供了Result这个枚举类型来处理这种可能失败的情况。它的定义是:

enum Result<T, E> {OK(T),Err(E),
}

它有两个泛型的类型参数,一个是T一个是E,它有两个变体,每个都关联了数据,OK关联了T,Err关联了E。泛型在第十章会讨论,现在只需要知道T是操作成功的情况下,OK变体里返回的数据的类型;E是在操作失败的情况下,Err变体里返回的错误的类型。

看个例子:

use std::fs::File;  
fn main() {  let f = File::open("6657.txt");  
}

这个代码的操作是打开文件,但这个文件不一定存在,所以说函数的运行可能会失败,所以File::open这个函数的返回值是Result枚举。这个Result里面第一个参数是std::fs::File,也就是文件类型(成功的时候返回);而第二个是std::io::Error,也就是io错误(失败的时候返回)

9.2.2. 用match处理Result

Option枚举一样,Result及其变体也是由预导入模块(prelude)带入作用域的,在写代码时不需要额外的引入。如下例:

use std::fs::File;  
fn main() {  let f = File::open("6657.txt");  let f = match f {  Ok(file) => file,  Err(e) => panic!("Error: {}", e),  };  
}

如果返回的值是Ok,那么就把它所关联的值绑定到file上再返回回去赋给f;如果返回的值是Err,那么就把错误信息绑定在e上由panic!宏打印出来并停止程序。

9.2.3. 匹配不同的错误

我们把上面的例子完善一下,如果出现找不到的情况,就创建这个文件,如果连创建都不成功或者是出现了除了找不到意外的情况(比如没有权限打开),才触发panic!

use std::fs::File;  
use std::io::ErrorKind;  fn main() {  let f = File::open("6657.txt");  let f = match f {  Ok(file) => file,  Err(e) => match e.kind() {  ErrorKind::NotFound => match File::create("6657.txt") {  Ok(fc) => fc,  Err(e) => panic!("Problem creating file: {:?}", e),  },  other_error => panic!("Problem opening file: {:?}", other_error),  },  };  
}
  • 在最外层仍然是如果f的值是Ok就把文件内容返回给f
  • 但在处理Err变体时有不同,Err所附带的数据的类型是std::io::Error,这个struct上有一个.kind()方法,通过这个方法可以获得std::io::ErrorKind这个类型值,它也是一个枚举,也是由标准库提供的,它里面的变体是用来描述io操作可能引起的不同错误
  • ErrorKind里面有一个变体ErrorKind::NotFound,表示文件不存在,这个时候就应该创建文件,在下面我们再讨论创建文件。除了ErrorKind::NotFound,也可能有其他错误(比如说没有权限读取),这里把其他错误赋给了other_error这个值,并由panic!打印出来然后停止程序。
  • 对于创建文件,可以使用File::create()这个函数,其参数就是文件名。而创建文件本身也有可能会失败(比如没权限),所以File::create()的返回值也是Result类型,那就再用一个match表达式来处理,如果是OK(创建成功),那就把OK关联的值,也就是这个新创建的文件呢的内容(内容肯定是空的,因为是新创建的)绑定在fc这个变量上返回赋给f;如果是Err(创建失败),就把Err所关联的错误信息绑定在e上用panic!打印出来并停止程序。

match确实用的比较多,但也比较原始,这里的套娃是其可读性大大降低(虽然对比其他语言可能可读性还要高一些)。而在第13章会讲一个概念叫做闭包(closure),Result类型有很多方法接受闭包作为参数,而且这些方法都是使用match实现的,能够使得代码更加简洁,我把使用闭包的代码例写在这里,但现在不会讲,到13章才会讲。

use std::fs::File;
use std::io::ErrorKind;fn main() {let greeting_file = File::open("6657.txt").unwrap_or_else(|error| {if error.kind() == ErrorKind::NotFound {File::create("6657.txt").unwrap_or_else(|error| {panic!("Problem creating the file: {error:?}");})} else {panic!("Problem opening the file: {error:?}");}});
}

9.2.4. unwrap方法

match表达式确实灵活有用,但写出来的代码也确实复杂了一些,而Result这个枚举类型本身也定义了许多的辅助方法来应对各式各样的任务,其中有一个常用的方法叫unwrap

如果unwrap接收到了OK,那么它就会把OK附带的值返回;而如果接收到了Err,那么unwrap就会调用panic!宏。比如说用unwrap重写9.2.2中的代码:

use std::fs::File;  fn main() {  let f = File::open("6657.txt").unwrap();  
}

unwrap就相当于match表达式的快捷方法。它的缺点就是错误信息不可以自定义。

9.2.5. expect方法

那如果我想要unwrap的快捷性,又想要自定义错误信息怎么办?针对这种情况,Rust提供了expect方法,如果你有印象的话,在第一章的猜数游戏中就用过这种方法。

试试用expect重写unwrap的代码例:

use std::fs::File;  fn main() {  let f = File::open("6657.txt").expect("file not found");  
}

http://www.mrgr.cn/news/82190.html

相关文章:

  • 【MongoDB详解】
  • Oracle DG备库数据文件损坏修复方法(ORA-01578/ORA-01110)
  • 《解密奖励函数:引导智能体走向最优策略》
  • 每日一学——监控工具(Grafana)
  • 【论文阅读笔记】SCI算法与代码 | 低照度图像增强 | 2022.4.21
  • Flutter Android修改应用名称、应用图片、应用启动画面
  • 【Rust自学】9.1. 不可恢复的错误以及panic!
  • 【Rust自学】8.6. HashMap Pt.2:更新HashMap
  • 深入探讨服务器虚拟化:架构、技术与应用
  • 我们能否使用 ANSYS SPEOS 测量水质?
  • Unity3D仿星露谷物语开发14之Custom Property Attribute
  • 偏移类窗口函数—— LAG()、LEAD()用法详解
  • 【Kafka 消息队列深度解析与应用】
  • 【Rust自学】8.5. HashMap Pt.1:HashMap的定义、创建、合并与访问
  • 【分布式缓存中间件Memcached原理与应用】
  • 面试题汇总
  • GXUOJ-算法-第四次作业(圆排列、连续邮资、n皇后、符号三角形)
  • 【非关系型数据库Redis 】 入门
  • primevue的<Menu>组件
  • 基于 Node.js 的 ORM(对象关系映射)工具——Sequelize介绍与使用,并举案例分析
  • 【循环神经网络】RNN介绍
  • 【容器化技术 Docker 与微服务部署】详解
  • 基于WSL在Windows下安装Ubuntu
  • C++ 设计模式:组合模式(Composite Pattern)
  • 智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之12 方案再探之3:特定于领域的模板 之2 首次尝试和遗留问题解决
  • 「Mac畅玩鸿蒙与硬件50」UI互动应用篇27 - 水果掉落小游戏