开发环境
- Windows 10
- Rust 1.67.1
- VS Code 1.75.1
项目工程
这里继续沿用上次工程rust-demo
带结果信息的可恢复错误
大多数错误并没有严重到需要程序完全停止的程度。有时,当一个函数失败时,它的原因是你可以很容易地解释和应对的。例如,如果你试图打开一个文件,但由于该文件不存在而导致操作失败,你可能想创建该文件,而不是终止该进程。
回顾前面章节中的 "用结果处理潜在的失败",结果枚举被定义为有两个变体,Ok和Err,如下例所示。
enum Result<T, E> {
Ok(T),
Err(E),
}
T和E是通用类型参数:我们将在后面章节中详细讨论通用类型。你现在需要知道的是,T代表在Ok变量中成功情况下将被返回的值的类型,E代表在Err变量中失败情况下将被返回的错误类型。因为Result有这些通用的类型参数,我们可以在许多不同的情况下使用Result类型和定义在它上面的函数,我们想返回的成功值和错误值可能不同。
让我们调用一个返回结果值的函数,因为这个函数可能会失败。在下例3中,我们尝试打开一个文件。
例3:文件名: src/main.rs
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt"); // hello.txt是否存在
println!("greeting_file_result = {:?}", greeting_file_result )
}
编译运行
cargo run
File::open 的返回类型是一个 Result<T, E>。通用参数T已经被File::open的实现填入了成功值的类型,即std::fs::File,它是一个文件句柄。错误值中使用的E的类型是std::io::Error。这个返回类型意味着对 File::open 的调用可能会成功,并返回一个我们可以读取或写入的文件句柄。该函数的调用也可能失败:例如,该文件可能不存在,或者我们可能没有访问该文件的权限。File::open函数需要有一种方法来告诉我们它是成功还是失败,同时给我们提供文件柄或错误信息。这些信息正是Result枚举所传达的。
在File::open成功的情况下,变量greeting_file_result中的值将是一个Ok的实例,包含一个文件柄。在失败的情况下,greeting_file_result中的值将是一个Err的实例,包含关于发生的错误类型的更多信息。
我们需要在上例2中的代码中添加一些内容,以便根据File::open返回的值采取不同的行动。下例3显示了一种使用基本工具处理结果的方法,即我们在之前章节讨论过的match表达式。
例4:文件名: src/main.rs
use std::fs::File;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result { // match表达式
Ok(file) => file,
Err(error) => panic!("Problem opening the file: {:?}", error),
};
}
请注意,和Option枚举一样,Result枚举和它的变体已经被前奏带入了范围,所以我们不需要在匹配类中的Ok和Err变体之前指定Result::。
当结果为Ok时,该代码将从Ok变量中返回内部文件值,然后我们将该文件句柄值赋给变量greeting_file。match后,我们可以使用文件句柄来读或写。
match的另一方面处理从File::open获取一个Err值的情况。在这个例子中,我们选择了panic!宏观。如果在我们的当前目录中没有名为hello.txt的文件,并且我们运行了这段代码,我们将会看到下面的输出panic!宏:
编译运行
cargo run
像往常一样,这个输出告诉我们到底哪里出错了。
不同错误的匹配
上例中的代码会panic!不管为什么File::open失败。但是,我们希望针对不同的失败原因采取不同的操作:如果File::open因为文件不存在而失败,我们希望创建该文件并将句柄返回给新文件。如果File::open由于任何其他原因失败—例如,因为我们没有打开文件的权限—我们仍然希望代码panic!就像上例中一样。为此,我们添加了一个内部match表达式,如下例5所示。
例5:文件名: src/main.rs
use std::fs::File;
use std::io::ErrorKind;
fn main() {
let greeting_file_result = File::open("hello.txt");
let greeting_file = match greeting_file_result {
Ok(file) => file,
Err(error) => match error.kind() { // match错误类型
ErrorKind::NotFound => match File::create("hello.txt") { // 创建hello,ext
Ok(fc) => fc,
Err(e) => panic!("Problem creating the file: {:?}", e),
},
other_err