复制项目(单个 main.rs 文件):https://github.com/frederikhors/iss-custom-err.
我正在尝试为我的应用程序创建自定义错误:
pub struct AppError {
message: String,
error: anyhow::Error, // In the future I would also avoid anyhow
}
我试图在我的代码中使用它,但正如你所看到的,我遇到了以下编译器错误,为什么?
我的
AppError
没有正确实现特征std::error::Error
吗?
我希望从
hyper
错误自动转换为 AppError
都是错误:错误特征,我错了吗?
error[E0277]: `?` couldn't convert the error to `AppError`
--> src\main.rs:20:44
|
20 | .body(Body::from(body))?;
| ^ the trait `From<hyper::http::Error>` is not implemented for `AppError`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `FromResidual<R>`:
<Result<T, F> as FromResidual<Result<Infallible, E>>>
<Result<T, F> as FromResidual<Yeet<E>>>
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, hyper::http::Error>>` for `Result<(), AppError>`
error[E0277]: `?` couldn't convert the error to `AppError`
--> src\main.rs:24:19
|
24 | .await?;
| ^ the trait `From<hyper::Error>` is not implemented for `AppError`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following other types implement trait `FromResidual<R>`:
<Result<T, F> as FromResidual<Result<Infallible, E>>>
<Result<T, F> as FromResidual<Yeet<E>>>
= note: required because of the requirements on the impl of `FromResidual<Result<Infallible, hyper::Error>>` for `Result<(), AppError>`
For more information about this error, try `rustc --explain E0277`.
我希望从超级错误到 AppError 的自动转换都是错误:错误特征,我错了吗?
是的。
Error
是一个 usage 特性,它就像 IntoIterator
:Vec
和 HashMap
都实现了它,但这并不意味着你可以将任意 Vec
转换为 HashMap
。
更不用说 Rust 会为你做到这一点:Rust 通常倾向于意向性,它避免了大型的多用途概念。所以
error
告诉你的是你可以显示类型,并且也许能够得到它的source
。除了转换为 Box<dyn Error>
之外,它没有提及任何有关转换的信息(因为 Error
是对象安全的)。
因此,正如编译器错误告诉您的那样,如果您希望 Rust(特别是
?
)执行转换,您需要实现From
特质。
thiserror
或 snafu
这样的库提供了更轻松地创建定制错误类型以及从现有错误类型进行转换的工具。
在不和谐时,一位好心的用户帮助我理解了。
我需要的是通用的
impl
:
impl<T: error::Error + Send + Sync + 'static> From<T> for AppError {
fn from(e: T) -> Self {
Self { message: e.to_string(), error: anyhow::Error::new(e) }
}
}
就是这样!
从 axum 示例来看,我们需要为 AppError 结构实现 From 特征
impl<E> From<E> for AppError
where
E: Into<anyhow::Error>,
{
fn from(err: E) -> Self {
Self(err.into())
}
}
这将允许 Result<,无论如何:Error> 自动转换为 Result<,AppError>
https://github.com/tokio-rs/axum/blob/main/examples/anyhow-error-response/src/main.rs