Error Handling

Unrecoverable Errors with panic!

Rust 的 可靠性:错误处理,大部分情况下:在编译时提示错误并处理

错误分类:

可恢复:例如文件未找到,可再次尝试

不可恢复:例如访问索引超出范围

默认情况下,当 panic 发生:

  • 程序展开调用栈 (工作量大)
  • Rust 沿着调用栈回走
  • 清理每个遇到的函数中的数据
  • 或 立即终止调用栈
  • 不清理内存,直接停止程序,内存需要 OS 进行清理

panic!

产生 panic 打印路径,行等信息

1
2
3
panic!("crash");

// thread 'main' panicked at src\main.rs:3:5:crash

panic!可能出现在我们写的代码中,我们所依赖的代码中

通过设置环境变量 RUST_BACKTRACE 可以得到回溯信息

Recoverable Errors with Result

Result 枚举

1
2
3
4
pub enum Result<T, E> {
Ok(T),
Err(E),
}

操作成功返回 Ok(T) 中的数据

操作失败返回 Err(E) 中的数据

例如打开一个文件, 返回 Result 类型

1
2
3
4
5
6
7
8
9
10
11
use std::fs::File;

fn main() {
let frs = File::open("some.txt");
let x = match frs {
Ok(file) => file,
Err(error) => {
panic!("Not find file {:#?}", error);
}
};
}

输出信息

1
2
3
4
5
6
thread 'main' panicked at src\main.rs:9:13:
Not find file Os {
code: 2,
kind: NotFound,
message: "系统找不到指定的文件。",
}

传播错误,将错误返回,让调用者决定如何处理

例如

1
2
3
4
5
6
7
8
9
10
11
12
13
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let frs = File::open(path);
let mut f = match frs {
Ok(file) => file,
Err(err) => return Err(err),
};

let mut s = String::new();
match f.read_to_string(&mut s) {
Ok(_) => Ok(s),
Err(e) => Err(e),
}
}

? 运算符 传播错误的一种快捷方式

例如,与上面功能一样

1
2
3
4
5
6
7
8
9
10
11
12
13
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let mut f = File::open(path)?;
let mut s = String::new();
f.read_to_string(&mut s)?;
Ok(s)
}

// let mut f = File::open(path)?;
// 等于
// let mut f = match frs {
// Ok(file) => file,
// Err(err) => return Err(err),
// };

? 作用于 Result ,成功即 Ok(T) 中的 T, 失败即 return Err

链式调用的方式

1
2
3
4
5
fn read_username_from_file(path: &str) -> Result<String, io::Error> {
let mut s = String::new();
File::open(path)?.read_to_string(&mut s)?;
Ok(s)
}

To panic! or Not to panic!

示例、 代码原型和测试都非常适合 panic

当我们比编译器知道更多的情况,当你有一些其他的逻辑来确保 Result 会是 Ok 值时,调用 unwrap 或者 expect 也是合适的

错误处理指导原则:在当有可能会导致有害状态的情况下建议使用 panic!

当错误预期会出现时,返回 Result 仍要比调用 panic! 更为合适