anyhow库提供了一个 anyhow::Error
类型,基于 std::error::Error
trait上面做的扩展,可以很方便的用于进行 Rust 程序的错误处理。
快速使用
如果需要在项目中添加 anyhow
依赖,可以使用如下命令:
cargo add anyhow
也可以直接编辑 Cargo.toml
文件,并添加一下内容:
[dependencies]
anyhow = "1.0"
注意:需要使用 rustc 1.39+版本
用法
- 使用
Result<T, anyhow::Error>
或者等效的anyhow::Result<T>
,来替换任何返回Result<T, E>
类型的函数返回值。
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(&config)?;
Ok(map)
}
- 附加context上下文可以有效的帮助开发人员排查问题到底出在哪里。如果没有更多的上下文信息,返回像“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)
- 支持使用
downcast
检查具体的错误类型,也可以做类型替换。
// 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),
}
如果使用Rust版本 ≥ 1.65,如果底层错误类型没有提供自己的错误类型,则会捕获并打印一个错误backtrace。为了查看backtrace信息,必须通过
std::backtrace
中描述的环境变量来启用backtrace:- 如果你想让panic和error都有backtrace,设置
RUST_BACKTRACE=1
- 如果你只想让 error 有 backtrace,设置
RUST_LIB_BACKTRACE=1
- 如果你只想让 panic 有 backtrace,设置
RUST_BACKTRACE=1
和RUST_LIB_BACKTRACE=0
- 如果你想让panic和error都有backtrace,设置
anyhow适用于任何实现了
std::error::Error
trait的错误类型,包括你在自己的 crate 中定义的错误类型。我们不绑定derive(Error)
宏,但是你可以使用thiserror库来快速定义错误。
use thiserror::Error;
#[derive(Error, Debug)]
pub enum FormatError {
#[error("Invalid header (expected {expected:?}, got {found:?})")]
InvalidHeader {
expected: String,
found: String,
},
#[error("Missing attribute: {0}")]
MissingAttribute(String),
}
- 可以使用
anyhow!
宏来构建一次性的错误信息,该宏支持通过字符串和一些变量插值来定义anyhow::Error
。
return Err(anyhow!("Missing attribute: {}", missing));
等效的也可以使用bail!
宏:
bail!("Missing attribute: {}", missing);
No-std支持
在 no_std 模式下,几乎所有相同的 API 都可用并且以相同的方式工作。 如果要在 no_std 模式下添加依赖 anyhow,请在 Cargo.toml
中禁用我们默认启用的std
功能。 需要一个全局allocator。
[dependencies]
anyhow = { version = "1.0", default-features = false }
由于基于?
的错误转换依赖于 std 下面的std::error::Error
trait,所以如果在 no-std 模式下,处理非 anyhow 错误类型时,需要显式的使用.map_err(Error::msg)
来返回一个 anyhow 的错误类型。