我有两种在外部包装箱中定义的错误类型。我们称它们为foo::Error
和bar::Error
。由于它们都是在外部定义的,因此我无法在两者之间直接建立From
或Into
转换。
在我自己的箱子中,我正在使用实现bar
的特征,该特征期望返回值为Result<T, bar::Error>
。在实现方法中,我从foo
调用函数,这些函数返回许多Result<T, foo::Error>
类型。
我想将这些foo::Error
错误映射到bar::Error
错误,这样我的特征实现就很整齐,但是我能做的最好的事情是创建一个单独的填充错误,然后再笨拙.map_err(ShimErr::from)?
。如果我在实现中调用许多foo::
函数,这可能会使我的代码混乱。
use foo;
use bar;
struct ShimErr(foo::Error);
impl From<foo::Error> for ShimErr {
fn from(e: foo::Error) -> Self {
Self(e)
}
}
impl From<ShimErr> for bar::Error {
fn from(e: ShimErr) -> Self {
Self{}
}
}
struct MyTraitImpl {}
impl bar::SomeTrait for MyTraitImpl {
fn do_something() -> Result<i32, bar::Error> {
// FIXME: THIS IS CLUNKY
let foo_val: i32 = foo::call_something().map_err(ShimErr::from)?;
Ok(foo_val * 2)
}
}
有更好的方法吗?在理想的世界中,将有一种方法可以只使用?
如果我删除了map_err
并尝试直接使用?
:
error[E0277]: `?` couldn't convert the error to `bar::Error`
--> shimtest.rs:32:49
|
32 | let foo_val: i32 = foo::call_something()?;
| ^ the trait `std::convert::From<foo::Error>` is not implemented for `bar::Error`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= help: the following implementations were found:
<bar::Error as std::convert::From<ShimErr>>
= note: required by `std::convert::From::from`
答案 0 :(得分:-1)
我处理与其他装箱不同的多个错误的方式是制作自己的Error
枚举,并直接使用它代替其他错误。
因此,可以创建一个既包含foo::Error
也包含foo::Error
的枚举,而不是只包含bar::Error
的元组结构。之后,您可以使用?
将所有错误转换为自定义枚举错误。
在某些情况下,我认为您仍然偶尔需要使用类似.map_err(Into::into)
的东西,但通常仅当返回的变量是带有外部错误的Result
时。
use bar::Error as BarError;
use foo::Error as FooError;
use std::fmt::{Display, Formatter, Result as FmtResult};
use std::result::Result as StdResult;
/// Common result type that uses the custom error
pub type Result<T> = StdResult<T, Error>;
/// Common error type used as a holder for errors from various other libraries.
#[derive(Debug)]
pub enum Error {
Bar(BarError),
Foo(FooError),
}
impl From<BarError> for Error {
fn from(err: BarError) -> Error {
Error::Bar(err)
}
}
impl From<FooError> for Error {
fn from(err: FooError) -> Error {
Error::Foo(err)
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter) -> FmtResult {
match *self {
Error::Bar(ref inner) => inner.fmt(f),
Error::Foo(ref inner) => inner.fmt(f),
}
}
}
impl StdError for Error {
fn description(&self) -> &str {
match *self {
Error::Bar(ref inner) => inner.description(),
Error::Foo(ref inner) => inner.description(),
}
}
}
现在,您可以按如下方式使用自定义Result
和Error
。
// this Result is now our custom Result type with custom error
// same as std::result::Result<i32, Error> (with Error as our custom error)
fn do_something() -> Result<i32> {
let foo_val: i32 = foo::call_something()?; // should convert to our custom error
Ok(foo_val * 2)
}
fn do_something_else() -> Result<i32> {
// directly returning a Result<> with a different error type will need map_err
foo::call_something().map_err(Into::into)
}