AnyHow & ThisError
两个库都是用来处理错误的好帮手,AnyHow简单方便,ThisError帮助我们创建完备的错误类型。
AnyHow
使用方法
-
在使用上来说,把任何可能会失败的函数(fallible function),把返回值的类型设置成
Result<T, anyhow::Error>
,或者等价的anyhow::Result<T>
。在函数内,就可以用
?
将任何implement了std::error::Error
的错误传递出来。use anyhow::Result;
fn get_cluster_info() -> Result<ClusterMap> {
let config = std::fs::read_to_string("cluster.json")?;
let map: ClusterMap = serde_json::from_str(
Ok(map)
} -
附加context来帮助触发了error的人来理解哪里不对了。尤其是一些low level的错误比如"No such file or directory"更需要增加一些信息。
use anyhow::{Context, Result};
fn main() -> Result<()> {
...
it.detach().context("Failed to detach the important thing")?;
let content = std::fs::read(path)
.with_context(|| format!("Failed to read instrs from {}", path))?;
...
}Error: Failed to read instrs from ./path/to/instrs.json
Caused by:
No such file or directory (os error 2) -
Downcasting支持by value, by shared reference, by mutable reference.
// If the error was caused by redaction, then return a
// tombstone instead of the content.
match root_cause.downcast_ref::<DataStoreError>() {
Some(DataStoreError::Censored(_)) => Ok(Poll::Ready(REDACTED_CONTENT)),
None => Err(error),
}
使用场景
如果是位于应用的最上层,或者简单写个脚本只想?
一把梭,那用Anyhow就可以了。
ThisError
使用方法
提供了过程宏帮助我们创建自定义的错误类型。他这里的过程宏有点DSL的感觉了。虽然他说他是支持Enum/Struct的,不过感觉大部分情况错误用Enum的和类型比较合适,表达各种各样的错误嘛。
#[derive(thiserror::Error)]
帮助我们实现std::error::Error
。#[error("format string")]
帮助我们实现Display
。#[from] xxError
帮助我们实现From<xxError>
,以及std::error::Error
中的source
方法。#[source]
帮助我们实现std::error::Error
中的source
方法(返回另一个错误类型,表示产生这个错误的根本原因)。#[backtrace]
帮助我们实现std::error::Error
中的backtrace
方法(貌似是做栈展开之用^backtrace)。#[error(transparent)]
帮我我们直接将错误传过来,典型用法是给未定义的错误进行兜底操作。
#[derive(Error, Debug)]
pub enum MyError {
...
#[error(transparent)]
Other(#[from] anyhow::Error),
}
使用场景
需要详细完备的错误信息,又懒得做手动去敲重复代码的重复性工作,比如一些底层库的构建。