You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
169 lines
6.9 KiB
169 lines
6.9 KiB
# Error Handling
|
|
|
|
Rust将错误分为两大类:**可恢复**和**不可恢复**的错误。对于可恢复的错误,例如找不到文件错误,我们可能只需要向用户报告问题并重试操作。不可恢复的错误总是 bug 的症状,例如试图访问数组末尾之外的位置,所以我们要立即停止程序。
|
|
|
|
大多数语言不区分这两种错误,并使用类似于异常的机制来处理。但是Rust没有异常,它使用类型Result<T, E>来处理可恢复的错误,使用 panic! 宏来停止程序执行当遇到不可恢复的错误。本章将先讨论调用 panic! ,然后讨论返回Result<T, E>的值。此外,我们还将探讨在决定是恢复错误还是停止执行时的考虑因素。
|
|
|
|
|
|
|
|
## panic
|
|
|
|
当发生恐慌时,程序开始展开,这意味着Rust向上走回堆栈并清理每个函数遇到的数据。然而,这种向上走和清理是很多工作。因此,Rust允许您选择立即中止的替代方法,这样可以在不清理的情况下结束程序。
|
|
|
|
```rust
|
|
// 发布模式下出现 panic 时中止。 修改Cargo.toml文件
|
|
|
|
[profile.release]
|
|
panic = 'abort'
|
|
```
|
|
|
|
|
|
|
|
### 简单的panic!
|
|
|
|
![image-20230129145332940](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129145332940.png)
|
|
|
|
第一行显示了我们的恐慌消息以及我们源代码中发生恐慌的位置:*src/main.rs:2:5*表示它是第二行,我们的*src/main.rs*文件的第五个字符。
|
|
|
|
|
|
|
|
### 使用panic!回溯
|
|
|
|
访问越界
|
|
|
|
![image-20230129150209627](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129150209627.png)
|
|
|
|
|
|
|
|
根据错误提示。设置`RUST_BACKTRACE` 环境变量以获取导致错误的确切原因的回溯。
|
|
|
|
![image-20230129151706140](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129151706140.png)
|
|
|
|
|
|
|
|
## 可恢复的错误Result
|
|
|
|
枚举Result的定义:
|
|
|
|
````rust
|
|
enum Result<T, E> {
|
|
Ok(T),
|
|
Err(E),
|
|
}
|
|
````
|
|
|
|
|
|
|
|
打开不存在的文件:
|
|
|
|
![image-20230129160739718](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129160739718.png)
|
|
|
|
|
|
|
|
创建文件后:
|
|
|
|
![image-20230129161343548](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129161343548.png)
|
|
|
|
|
|
|
|
## 匹配不同的错误
|
|
|
|
通过代码定位到具体的错误,而非自己去查找、
|
|
|
|
![image-20230129162635694](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230129162635694.png)
|
|
|
|
|
|
|
|
#### 不使用match
|
|
|
|
`unwrap_or()`方法接受一个默认值作为参数,如果Result的值是Ok,则返回其内部的值,如果Result的值是Err,则返回默认值。这个方法适用于错误情况下提供一个固定的默认值的情况。
|
|
|
|
`unwrap_or_else()`方法接受一个回调函数作为参数,如果Result的值是Ok,则返回其内部的值,如果Result的值是Err,则调用传递给unwrap_or_else的回调函数,并返回其返回值。回调函数允许对错误情况进行自定义处理。
|
|
|
|
![image-20230130092333945](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130092333945.png)
|
|
|
|
|
|
|
|
## unwrap and expect
|
|
|
|
`unwrap()` 是一种方法,它返回包含的值或在错误时引发错误。它用于您确信结果将是“Ok”的情况,并希望如果不是则崩溃程序。
|
|
|
|
![image-20230130100535038](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130100535038.png)
|
|
|
|
|
|
|
|
使用 expect,允许我们选择`panic!`错误消息。相较于unwrap,**expect使用的更多**。
|
|
|
|
![image-20230130100857207](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130100857207.png)
|
|
|
|
|
|
|
|
## 传播错误
|
|
|
|
当一个函数的实现调用可能失败的操作时,与其在函数内部处理错误,您可以将错误返回给调用代码,以便它可以决定如何处理。这称为传播错误,并给调用代码提供了更多的控制权,因为在调用代码中可能有更多的信息或逻辑来决定如何处理错误,而您在代码的上下文中可能不具备这些信息或逻辑。
|
|
|
|
![image-20230130114134605](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130114134605.png)
|
|
|
|
运行(包含数据):
|
|
|
|
![image-20230130153825415](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130153825415.png)
|
|
|
|
|
|
|
|
运行(不存在文件):
|
|
|
|
![image-20230130154105950](C:\Users\admin\AppData\Roaming\Typora\typora-user-images\image-20230130154105950.png)
|
|
|
|
此函数可以以更短的方式编写,但是我们首先要手动执行很多操作,以探索错误处理。
|
|
|
|
|
|
|
|
## ?运算符--传播错误快捷方式
|
|
|
|
以下代码同前文代码作用完全相同
|
|
|
|
![image-20230206224411662](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206224411662.png)
|
|
|
|
|
|
|
|
### 使用立即链接进一步精简代码
|
|
|
|
![image-20230206225432532](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206225432532.png)
|
|
|
|
|
|
|
|
### 使用系统函数(fs::read_to_string)
|
|
|
|
![image-20230206230153864](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206230153864.png)
|
|
|
|
## ?可以出现的位置
|
|
|
|
该`?`运算符只能用在返回类型与所用值**兼容**的函数,若尝试在main函数(无返回值时)中使用`?`是不可以的。
|
|
|
|
![image-20230206231105650](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206231105650.png)
|
|
|
|
|
|
|
|
### 使用?with option<T>
|
|
|
|
在给定文本中查找第一行的最后一个字符:
|
|
|
|
![image-20230206232023649](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206232023649.png)
|
|
|
|
|
|
|
|
如果`text`是空字符串,则此调用`next`将返回`None`,在这种情况下我们使用`?`停止并`None`从 返回`last_char_of_first_line`。如果`text`不是空字符串,`next`将返回一个`Some`包含 中第一行的字符串切片的值`text`。
|
|
|
|
`chars`字符串切片以获取其字符的迭代器。调用`last`以返回迭代器中的最后一项。
|
|
|
|
|
|
|
|
## 修改main函数来适配?
|
|
|
|
![image-20230206233206129](C:\Users\10074\AppData\Roaming\Typora\typora-user-images\image-20230206233206129.png)
|
|
|
|
`Box<dyn Error>`类型是一个*特征对象*, 目前可以理解为“任何类型的错误”。`?`允许在具有错误类型的函数中使用`Result` 值,因为它允许提前返回任何值。即使此函数的主体将只返回 类型的错误,通过指定,即使返回其他错误的更多代码添加到 的主体,此签名也将继续正确。
|
|
|
|
当main函数返回Result<(), E>时,如果main返回Ok(()),可执行文件将以0值退出,如果main返回Err值,则将以非0值退出。C语言编写的可执行文件在退出时返回整数:成功退出的程序返回整数0,错误退出的程序返回非0的整数。Rust还从可执行文件中返回整数以与此约定兼容。
|
|
|
|
main函数可以返回任何实现std::process:: terminate特征的类型,该特征包含一个返回ExitCode的函数报告。有关为自己的类型实现terminate特征的更多信息,参阅标准库[文档](https://doc.rust-lang.org/std/process/trait.Termination.html)。
|
|
|