rust_learning/panic/
result.rs

1use std::fs;
2use std::fs::File;
3use std::io::{ErrorKind, Read};
4
5/// 处理`Result`类型的结果,如果文件成功打开,则继续程序的后续操作;
6pub fn result_def() {
7    let f = File::open("hello.txt");
8    match f {
9        Ok(file) => file,
10        Err(error) =>
11            match error.kind() {
12                ErrorKind::NotFound => match File::create("hello.txt") {
13                    Ok(fc) => fc,
14                    Err(e) => panic!("Error"),
15                }
16                _ => panic!("Error"),
17            }
18    };
19}
20
21/// 尝试打开名为"hello.txt"的文件,并处理潜在的错误
22///
23/// 使用`unwrap`方法来处理`Result`类型的结果,如果文件成功打开,则继续程序的后续操作;
24/// 如果文件打开失败(例如文件不存在),则程序会自动终止并返回错误。
25pub fn result_unwrap() {
26    // 使用unwrap方法直接处理文件打开的结果,避免显式地处理错误
27    let f = File::open("hello.txt").unwrap();
28}
29
30/// 尝试打开名为"hello.txt"的文件,并返回一个包含文件内容的字符串,如果文件打开失败,则返回相应的错误。
31pub fn result_expect() {
32    // 使用expect方法来处理文件打开的结果,并在文件打开失败时返回自定义的错误信息
33    // 在生产级别的代码中,大部分 Rustaceans 选择 expect 而不是 unwrap 并提供更多关于为何操作期望是一直成功的上下文。
34    // 如此如果该假设真的被证明是错的,你也有更多的信息来用于调试。
35    let f = File::open("hello.txt").expect("Failed to open hello.txt");
36}
37
38/// 尝试打开名为"hello.txt"的文件,并读取其中的内容,如果文件打开失败,则返回相应的错误。
39pub fn result_propagating_panic() {
40    let username = read_username_from_file();
41    let username = match username {
42        Ok(username) => username,
43        Err(error) => panic!("Failed to read username: {}", error),
44    };
45    println!("{}", username);
46}
47
48/// 尝试打开名为"hello.txt"的文件,并读取其中的内容,如果文件打开失败,则返回相应的错误。
49pub fn read_username_from_file() -> Result<String, std::io::Error> {
50    let f = File::open("hello.txt");
51    let mut f = match f {
52        Ok(file) => file,
53        Err(e) => match e.kind() {
54            ErrorKind::NotFound => match File::create("hello.txt") {
55                Ok(fc) => fc,
56                Err(e) => return Err(e),
57            },
58            _ => return Err(e),
59        },
60    };
61    let mut s = String::new();
62    match f.read_to_string(&mut s) {
63        Ok(_) => Ok(s),
64        Err(e) => Err(e),
65    }
66}
67
68// ?
69// ? 运算符只能被用于返回值与 ? 作用的值相兼容的函数。
70// 比如说函数的返回值必须是 Result 才能与这个 return 相兼容。
71/// 尝试打开名为"hello.txt"的文件,并读取其中的内容,如果文件打开失败,则返回相应的错误。
72pub fn read_username_from_file_question_mark() -> Result<String, std::io::Error> {
73    // Result 值之后的 ? 被定义为与示例 9-6 中定义的处理 Result 值的 match 表达式有着完全相同的工作方式。
74    // 如果 Result 的值是 Ok,这个表达式将会返回 Ok 中的值而程序将继续执行。
75    // 如果值是 Err,Err 将作为整个函数的返回值,就好像使用了 return 关键字一样,这样错误值就被传播给了调用者。
76
77    // ? 运算符所使用的错误值被传递给了 from 函数,它定义于标准库的 From trait 中,其用来将错误从一种类型转换为另一种类型。
78    // 当 ? 运算符调用 from 函数时,收到的错误类型被转换为由当前函数返回类型所指定的错误类型。
79    // 这在当函数返回单个错误类型来代表所有可能失败的方式时很有用,即使其可能会因很多种原因失败。
80    let mut s = String::new();
81    File::open("hello.txt")?.read_to_string(&mut s)?;
82    Ok(s)
83}
84
85/// 使用标准库提供的 read_to_string 方法
86pub fn read_username_from_file_std_lib() -> Result<String, std::io::Error> {
87    fs::read_to_string("hello.txt")
88}
89