这里不复述文档和教程中有的内容, 比如Result
之类的细节, 可以自行看文档内容:
参考资料: https://www.philipdaniels.com/blog/2019/defining-rust-error-types/
1. Rust中自定义Error的方式
1.1 定义一个错误类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #[derive(Debug)] pub enum MyErorType { Io(io::Error), Git(git2::Error), Regular(ErrorKind), Custom(String) }
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum ErrorKind { NotFound, NotAuthorized, }
impl ErrorKind { fn as_str(&self) -> &str { match *self { ErrorKind::NotFound => "not found", ErrorKind::NotAuthorized => "not authorized" } } }
|
1.2 实现Error
和Display
这两个trait
Error
只允许返回静态字符串常量
1 2 3 4 5 6 7 8 9 10
| impl Error for MyErrorType { fn description(&self) -> &str { match *self { MyErrorType::Io(ref err) => err.description(), MyErrorType::Git(ref err) => err.description(), MyErrorType::Regular(ref err) => err.as_str(), MyErrorType::Custom(ref err) => err, } } }
|
fmt::Display
更为灵活一点
1 2 3 4 5 6 7 8 9 10
| impl fmt::Display for MyErrorType { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { MyErrorType::Io(ref err) => err.fmt(f), MyErrorType::Git(ref err) => err.fmt(f), MyErrorType::Regular(ref err) => write!(f, "A regular error occurred {:?}", err), MyErrorType::Custom(ref err) => write!(f, "A custom error occurred {:?}", err), } } }
|
1.3 为external error type实现From
1 2 3 4 5 6 7 8 9 10 11
| impl From<io::Error> for MyErrorType { fn from(err: io::Error) -> MyErrorType { MyErrorType::Io(err) } }
impl From<io::Error> for MyErrorType { fn from(err: git2::Error) -> MyErrorType { MyErrorType::Git(err) } }
|
使用起来就可以这样, 在捕获异常的代码片段中:
1.4 可选: 创建一个Result别名
1
| pub type Result<T> = std::result::Result<T, MyErrorType>;
|
1.5 使用自定义的类型:
1 2 3 4 5 6 7 8 9
| fn some_func() -> Result<usize> { let _f = std::fs::File::create("aa")?; let _g = Respository::init("/path/to/repo")?;
Err(MyErrorType::Regular(ErrorKind::NotAuthorized)); }
|
2. Rust 中使用 thiserror
和 anyhow
(简洁, 好用)
thiserror
文档: https://docs.rs/thiserror/latest/thiserror/
anyhow
文档: https://github.com/dtolnay/anyhow
这两个库主要还是为了某些库里处理数量众多的异常类型, 可以解决兼容, 但还需要额外处理
1 2 3 4 5 6
| use anyhow::Result
fn get() -> Result<()> {
}
|
3. 错误类型映射
前面所作的努力只是为了兼容, 但是rust并不会主动去做, 转换工作还是得自己来
3.1 map_err
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| use std::env;
fn double_arg(mut argv: env::Args) -> Result<i32, String> { argv.nth(1) .ok_or("Please give at least one argument".to_owned()) .and_then(|arg| arg.parse::<i32>().map_err(|err| err.to_string())) .map(|n| 2 * n) }
fn main() { match double_arg(env::args()) { Ok(n) => println!("{}", n), Err(err) => println!("Error: {}", err), } }
|
1 2 3 4 5
| cmdline.insert_str(boot_args) .map_err(BootSourceConfigError::InvalidKernelCommandLine) .map_err(VmmActionError::BootSource) .map_err(CLIError::BootSource)?;
|