Rust 可恢复错误17 Mar 2025 | 6 分钟阅读 - 可恢复错误是指那些不那么严重,以至于不必完全停止程序的错误。可以被处理的错误被称为可恢复错误。
- 它由 Result<T, E> 表示。 Result<T, E> 是一个枚举,由两个变体组成,即 OK<T> 和 Err<E>。它描述了可能的错误。
OK<T>:'T' 是一个值的类型,它在成功情况下返回 OK 变体。这是一个预期的结果。 Err<E>:'E' 是一个错误的类型,它在失败情况下返回 ERR 变体。这是一个非预期的结果。 - 在上述情况下,Result 是枚举类型,OK<T> & Err<E> 是枚举类型的变体,其中 'T' 和 'E' 是泛型类型参数。
- 'T' 是一个值的类型,它将在成功情况下返回,而 'E' 是一个错误的类型,它将在失败情况下返回。
- Result 包含泛型类型参数,因此我们可以使用 Result 类型和标准库中定义的函数在许多不同的情况下,其中成功和失败的值可能会有所不同。
让我们看一个返回 Result 值的简单示例 输出 
在上面的例子中,Rust 编译器显示类型不匹配。 'f' 是 u32 类型,而 File::open 返回 Result<T, E> 类型。上面的输出表明成功值的类型是 std::fs::File,错误值的类型是 std::io::Error。 注意- File::open 的返回类型要么是成功值,要么是失败值。如果 file::open 成功,则返回文件句柄,如果 file::open 失败,则返回错误值。 Result 枚举提供了此信息。
- 如果 File::open 成功,那么 f 将具有包含文件句柄的 OK 变体,如果 File::open 失败,那么 f 将具有包含与错误相关的信息的 Err 变体。
使用 Match 表达式处理 Result 变体。让我们看一个 match 表达式的简单示例 输出 
程序说明 - 在上面的例子中,我们可以直接访问枚举变体,而无需在 OK 和 Err 变体之前使用 Result::。
- 如果结果是 OK,那么它返回文件并将其存储在 'f' 变量中。匹配之后,我们可以在文件中执行读取或写入操作。
- match 的第二个分支处理 Err 值。如果 Result 返回 Error 值,那么 panic! 运行并停止程序的执行。
错误时 Panic:unwrap()- Result<T, E> 有许多方法来提供各种任务。其中一个方法是 unwrap() 方法。 unwrap() 方法是 match 表达式的快捷方法。 unwrap() 方法和 match 表达式的工作方式相同。
- 如果 Result 值是 OK 变体,那么 unwrap() 方法返回 OK 变体的值。
- 如果 Result 值是 Err 变体,那么 unwrap() 方法调用 panic! 宏。
让我们看一个简单的例子 输出 
在上面的例子中,unwrap() 方法会自动调用 panic 宏,panic! 显示错误信息。 错误时 Panic:expect()- expect() 方法的行为与 unwrap() 方法相同,即,两种方法都调用 panic! 来显示错误信息。
- expect() 方法和 unwrap() 方法之间的区别在于,错误消息作为参数传递给 expect() 方法,而 unwrap() 方法不包含任何参数。 因此,我们可以说 expect() 方法可以更轻松地跟踪 panic! 的来源。
让我们看一个 expect() 的简单示例 输出 
在上面的输出中,错误消息显示在输出屏幕上,这是我们在程序中指定的,即 "无法找到文件 hello.txt",这使我们更容易找到错误来源的代码。 如果我们包含多个 unwrap() 方法,那么很难找到哪个 unwrap() 方法导致 panic!,因为 panic! 为所有错误显示相同的错误消息。 传播错误传播错误是一种机制,其中错误从一个函数转发到另一个函数。 错误被传播到调用函数,在那里可以获得更多信息,以便可以处理错误。 假设我们有一个名为 'a.txt' 的文件,它包含文本 "javaTpoint." 我们想要创建一个程序来执行此文件的读取操作。 让我们来处理这个例子。 让我们看一个简单的例子 输出 
程序说明 - read_username_from_file() 函数返回 Result<T, E> 类型的值,其中 'T' 是 String 类型,'E' 是 io:Error 类型。
- 如果函数成功,则返回一个包含 String 的 OK 值,如果函数失败,则返回一个 Err 值。
- 此函数首先调用 File::open 函数。 如果 File::open 函数失败,那么 match 的第二个分支将返回 Err 值,如果 File::open 函数成功,那么它将文件句柄的值存储在变量 f 中。
- 如果 File::open 函数成功,那么我们创建一个 String 变量。 如果 read_to_string() 方法成功,那么它返回文件的文本,否则返回错误信息。
- 假设我们有一个外部文件,名称为 'a.text',包含文本 "javaTpoint."。 因此,该程序读取文件 'a.text' 并显示文件的内容。
传播错误的快捷方式:'?' 运算符使用 '?' 运算符减少了代码的长度。 '?' 运算符是 match 表达式的替代,意味着 '?' 运算符的工作方式与 match 表达式相同。 假设我们有一个名为 'a.txt' 的文件,它包含文本 "javaTpoint." 我们想要创建一个程序来执行此文件的读取操作。 让我们来处理这个例子。 让我们看一个简单的例子。 输出 
在上面的例子中,'?' 运算符用于 Result 值类型之前。 如果 Result 是 OK,那么它返回 OK 变体的值,如果 Result 是 Err,那么它返回错误信息。 '?' 运算符和 match 表达式之间的区别- 与 '?' 运算符一起使用的错误会通过 'from' 函数移动,'from' 函数在标准库的 from trait 中定义。
- 当 '?' 运算符调用 'from' 函数时,此函数将错误类型转换为当前函数返回类型中定义的错误类型。
- 如果没有错误发生,那么任何函数末尾的 '?' 运算符返回 OK 的值,如果发生错误,则返回 Err 的值。
- 它使函数的实现更简单。
在 '?' 运算符之后链接方法调用通过在 '?' 运算符之后链接方法调用,我们甚至可以缩短程序的代码。 让我们看一个简单的例子 输出 
程序说明 在上面的例子中,我们将 read_to_string() 的调用链接到 File::open("a.txt")? 的调用结果。我们将 '?' 运算符放在 read_to_string() 调用的末尾。 如果两个函数,即 read_to_string() 和 File::open("a.txt") 都成功,则返回 OK 值,否则返回错误值。 '?' 运算符的限制'?' 运算符只能在返回 Result 类型值的函数中使用。 因为 '?' 运算符的工作方式与 match 表达式类似。 match 表达式仅适用于 Result 返回类型。 让我们通过一个简单的例子来理解这一点。 输出 
|