Rust 错误处理

错误是程序中会导致不期望输出的意外行为或事件。

在 Rust 中,错误分为两类:

  • 不可恢复错误
  • 可恢复错误

Rust 中的不可恢复错误

不可恢复错误是程序会停止执行的错误。顾名思义,我们无法从不可恢复错误中恢复。

这些错误称为 **panic**,可以通过显式调用 `panic!` 宏来触发。

让我们看一个使用 `panic!` 宏的示例。

示例 1:使用 panic! 宏的 Rust 不可恢复错误

fn main() {
    println!("Hello, World!");

    // Explicitly exit the program with an unrecoverable error
    panic!("Crash");
}

输出

Hello, World!
thread 'main' panicked at 'Crash', src/main.rs:5:5

在这里,调用 `panic!` 宏会导致不可恢复错误。

thread 'main' panicked at 'Crash', src/main.rs:5:5

请注意,程序仍然会执行 `panic!` 宏之上的表达式。在错误消息显示之前,我们仍然可以看到 `Hello, World!` 打印到屏幕上。

`panic!` 宏将错误消息作为参数。


示例 2:Rust 不可恢复错误

不可恢复错误也会通过执行可能导致代码 panic 的操作来触发。例如,访问数组越界会引起 panic。

fn main() {
    let numbers = [1, 2 ,3];

    println!("unknown index value = {}", numbers[3]);
}

错误

error: this operation will panic at runtime
 --> src/main.rs:4:42
  |
4 |     println!("unknown index value = {}", numbers[3]);
  |                                          ^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3
  |

在这里,Rust 会阻止我们编译程序,因为它知道该操作会在运行时 panic。

数组 `numbers` 在索引 **3** 处没有值,即 `numbers[3]`。


可恢复错误

可恢复错误是不会导致程序停止执行的错误。大多数错误都是可恢复的,我们可以根据错误类型轻松采取相应措施。

例如,如果您尝试打开一个不存在的文件,您可以创建该文件,而不是停止程序执行或通过 panic 退出程序。

让我们看一个例子。

use std::fs::File;

fn main() {
    let data_result = File::open("data.txt");

// using match for Result type let data_file = match data_result { Ok(file) => file, Err(error) => panic!("Problem opening the data file: {:?}", error), };
println!("Data file", data_file); }

如果 `data.txt` 文件存在,则 **输出** 为:

Data file: File { fd: 3, path: "/playground/data.txt", read: true, write: false }

如果 `data.txt` 文件不存在,则 **输出** 为:

thread 'main' panicked at 'Problem opening the data file: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:8:23

Result 枚举

在上面的示例中,`File::open('data.txt')` 的返回类型是 `Result`。

在 Rust 中,`Result` 类型返回一个值或一个错误。它是一个 `enum` 类型,有两种可能的变体:

  • `Ok(T)` → 操作成功,值为 `T`
  • `Err(E)` → 操作失败,错误为 `E`

这里,`T` 和 `E` 是泛型类型。要了解有关泛型或泛型类型的更多信息,请访问 Rust 泛型

查看 `Result` 枚举是否有值或错误的最基本方法是使用 `match` 表达式进行模式匹配。

// data_file is a Result<T, E>
match data_result {
    Ok(file) => file,
    Err(error) => panic!("Problem opening the data file: {:?}", error),
 };

当结果为 `Ok` 时,此代码将返回 `file`,当结果为 `Err` 时,它将返回 `panic!`。

要了解有关模式匹配的更多信息,请访问 Rust 模式匹配


Option 枚举

`Option` 类型或 `Option` 类型与 `Result` 类似,是一个 `enum` 类型,有两种可能的变体:

  • `None` → 表示失败且无值
  • `Some(T)` → 一个类型为 `T` 的值

我们来看一个例子:

fn main() {
    let text = "Hello, World!";
    
    let character_option = text.chars().nth(15);
    
// using match for Option type let character = match character_option { None => "empty".to_string(), Some(c) => c.to_string() };
println!("Character at index 15 is {}", character); }

输出

Character at index 15 is empty

这里,方法 `text.chars().nth(15)` 返回一个 `Option`。因此,要从 `Option` 中取出值,我们使用 `match` 表达式。

在上面的示例中,字符串 `text` 的第 15 个索引不存在。因此,`Option` 类型返回 `None`,与 `"empty"` 字符串匹配。

None => "empty".to_string() 

如果我们获取字符串 `text` 的第 11 个索引,`Option` 枚举将返回 `Some(c)`,其中 `c` 是第 11 个索引处的字符。

让我们更新上面的示例,找出字符串中的第 11 个索引。

fn main() {
    let text = "Hello, World!";
    
let character_option = text.chars().nth(11);
// using match for Option type let character = match character_option { None => "empty".to_string(), Some(c) => c.to_string() }; println!("Character at index 11 is {}", character); }

输出

Character at index 11 is d

Rust 中 Result 和 Option 枚举的区别

`Option` 枚举可以返回 `None`,这可以表示失败。

但是,有时表达操作失败的原因非常重要。因此,我们有了 `Result` 枚举,它提供了 `Err` 并说明了操作失败的原因。

简而言之:

  • `Option` 是关于 `Some` 或 `None`(有值或无值)
  • `Result` 是关于 `Ok` 或 `Err`(成功结果或错误结果)

我们的高级学习平台,凭借十多年的经验和数千条反馈创建。

以前所未有的方式学习和提高您的编程技能。

试用 Programiz PRO
  • 交互式课程
  • 证书
  • AI 帮助
  • 2000+ 挑战