Rust里的错误处理主要分两种: Panic
和 Result
💀Panic
- 不像C++的未定义操作,
painc
时的操作顺序:- 打印错误信息, 如果定义了
RUST_BACKSTRACE=1
, 还将打印堆栈; - 栈回溯, 按照堆栈顺序销毁资源, 所有类型(含自定义类型)的
drop
方法被调用; - 线程退出,
Panic
是线程级, 如果主线程崩了, 整个进程结束, 否则其它线程还会继续.
- 打印错误信息, 如果定义了
- 可以用
std::panic::catch_unwind()
捕获panic
时的stack unwinding
, 这也是Rust test的做法. - 当C/C++等其它语言调用Rust代码时可以用
std::panic::catch_unwind()
捕获, 因为unwinding 非Rust code 的行为是未定义的. std::panic::catch_unwind()
只能用于恢复堆栈, 不要尝试着继续运行.- 如果清理过程中
drop
方法再次panic, 则Rust不会再尝试恢复堆栈unwind stack, 直接abort
.
⚖️Result<T,E>
1 | pub enum Result<T, E> { |
T, E 分别定义Ok和Err包含的类型:
- Ok(T)
- Err(E)
Result有两个方法:
.as_ref()
和.as_mut()
分别把Result<T, E>
转为Result<&T, &E>
和Result<&mut T, &mut E>
从而避免销毁它或者move.fn remove_file(path: &Path) → Result<()>
, 这里的Result是别名(aliases), 需要看对应的模块的public Result定义:1
pub type Result<T> = result::Result<T, Error>
通过
println!("{:?}", err);
可以查看到更多的技术性错误信息;err.description()
以&str
方式返回错误信息;err.cause()
返回Option<&Error>
: 内部错误详细信息.
用
?
向上抛出Err, 只能用于返回Result
的函数errorchain
crate 可以用于定义error type, 方便?
抛出不同类型Err
Custom Error Type
通常直接定义错误信息结构体, 然后用
Err()
抛出就够了1
2
3
4
5
6
7
8
pub struct JsonError {
pub message: String,
pub line: usize,
pub column: usize,
}
return Err(JsonError {...});
如果希望和标准库的错误类型表现一致, 还需要定义
fmt::Display
和Error
的trait.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16use std;
use std::fmt;
// Errors should be printable
imple fmt::Display for JsonError {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
write!(f, "{} ({}:{})", self.message, self.line, self.column);
}
}
// Errors should implement the std::error::Error trait.
impl std::error::Error for JsonError {
fn description(&self) -> &str {
&self.message
}
}