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的函数errorchaincrate 可以用于定义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
}
}