Rust错误处理
- Rust错误类型:Rust区分不可恢复错误和可恢复错误。不可恢复错误使用
panic!
宏触发,会停止程序执行;可恢复错误通常用Result
和Option
枚举处理,允许程序响应错误。 - 不可恢复错误的处理:不可恢复错误(panic)可由数组索引越界等操作触发,也可显式通过
panic!
宏调用。这种错误通常表示严重问题,需立即终止程序。 - 可恢复错误的处理:可恢复错误使用
Result<T, E>
枚举处理,其中Ok(T)
表示成功,而Err(E)
表示失败。Option<T>
枚举用于可能没有值的情况,Some(T)
表示有值,None
表示无值。
错误是程序中的意外行为或事件,会产生不想要的输出。
在 Rust 中,错误分为两类:
- 不可恢复的错误
- 可恢复的错误
Rust 中的不可恢复错误
不可恢复的错误是导致程序停止执行的错误。顾名思义,我们无法从不可恢复的错误中恢复。
这些错误被称为 panic,可以通过调用 panic!
宏显式触发。
让我们看一个使用 panic!
宏的例子。
示例 1:Rust 中带有 panic! 宏的不可恢复错误
fn main() {
println!("Hello, World!");
// 显式退出程序并触发一个不可恢复错误
panic!("Crash");
}
输出
Hello, World!
线程 'main' 在 'Crash', src/main.rs:5:5 处惊慌失措
这里,调用 panic!
宏导致了一个不可恢复的错误。
线程 'main' 在 'Crash', src/main.rs:5:5 处惊慌失措
注意程序仍然执行了 panic!
宏以上的表达式。我们仍然可以在错误消息之前看到屏幕上打印出的 Hello, World!
。
panic!
宏接受一个错误消息作为参数。
示例 2:Rust 中的不可恢复错误
不可恢复的错误也会在我们执行可能导致代码panic的操作时触发。例如,访问数组超出其索引将导致panic。
fn main() {
let numbers = [1, 2 ,3];
println!("未知索引值 = {}", numbers[3]);
}
错误
error: 这个操作将在运行时panic
--> src/main.rs:4:42
|
4 | println!("未知索引值 = {}", numbers[3]);
| ^^^^^^^^^^ 索引越界:长度为 3 但索引为 3
|
这里,Rust 阻止我们编译程序,因为它知道该操作将在运行时panic。
数组 numbers
在索引 3 处没有值,即 numbers[3]
。
可恢复错误
可恢复错误是不会停止程序执行的错误。大多数错误是可恢复的,我们可以根据错误类型采取相应的行动。
例如,如果您尝试打开一个不存在的文件,您可以创建该文件,而不是停止程序执行或使用panic退出程序。
让我们看一个例子。
use std::fs::File;
fn main() {
let data_result = File::open("data.txt");
// 使用 match 对 Result 类型进行处理
let data_file = match data_result {
Ok(file) => file,
Err(error) => panic!("打开数据文件时出现问题: {:?}", error),
};
println!("数据文件", data_file);
}
如果 data.txt
文件存在,输出为:
数据文件: File { fd: 3, path: "/playground/data.txt", read: true, write: false }
如果 data.txt
文件不存在,输出为:
线程 'main' 在 '打开数据文件时出现问题: Os { code: 2, kind: NotFound, message: "No such file or directory" }', src/main.rs:8:23 处惊慌失措
Result 枚举
在上述示例中,File::open('data.txt')
的返回类型是 Result<T, E>
。
Result<T, E>
类型在 Rust 中返回一个值或错误。它是一个 enum
类型,有两种可能的变体。
Ok(T)
→ 操作成功,带有值T
Err(E)
→ 操作失败,带有错误E
这里,T
和 E
是泛型类型。要了解更多关于
泛型或泛型类型,请访问 Rust 泛型。
判断 Result
枚举是值还是错误的最基本方法是使用 match
表达式进行模式匹配。
// data_file 是一个 Result<T, E> 类型
match data_result {
Ok(file) => file,
Err(error) => panic!("打开数据文件时出现问题: {:?}", error),
};
当结果是 `Ok` 时,这段代码将返回 `file`;当结果是 `Err` 时,它会触发 `panic!`。
要了解更多关于模式匹配,请访问 [Rust 模式匹配](/tutorials/rust/pattern-matching)。
## Option 枚举
`Option` 类型或 `Option<T>` 类型是一个枚举类型,就像 `Result` 一样,它有两种可能的变体。
- `None` → 表示没有值的失败情况
- `Some(T)` → 类型为 `T` 的值
我们来看一个例子,
```rust exec
fn main() {
let text = "Hello, World!";
let character_option = text.chars().nth(15);
// 使用 match 表达式处理 Option 类型
let character = match character_option {
None => "empty".to_string(),
Some(c) => c.to_string()
};
println!("索引 15 处的字符是 {}", character);
}
输出
索引 15 处的字符是 empty
这里,方法 text.chars().nth(15)
返回一个 Option<String>
。因此,为了从 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);
// 使用 match 表达式处理 Option 类型
let character = match character_option {
None => "empty".to_string(),
Some(c) => c.to_string()
};
println!("索引 11 处的字符是 {}", character);
}
输出
索引 11 处的字符是 d