假设有一个外部模块(由第三方库提供):
请注意,我无法实现
现在我要实现
为了使其编译,我可以明确地使用
pub mod external_module {
#[derive(Debug)]
pub struct ExternalError;
pub trait SomeTrait {
fn do_stuff(&self) -> Result<i32, ExternalError>;
}
}
我需要在我的代码中实现SomeTrait
。我的代码可能会遇到一些内部错误,因此我定义了自己的错误类型并使其可转换成ExternalError
:
struct MyError;
impl Into<ExternalError> for MyError {
fn into(self) -> external_module::ExternalError {
ExternalError {}
}
}
请注意,我无法实现
from<MyError> for ExternalError
,因为 ExternalError
是在我的命名空间之外定义的(实际上甚至在我的板条箱之外)。现在我要实现
SomeTrait
:fn do_my_things() -> Result<(), MyError> {
Ok(())
}
struct MyStruct;
impl SomeTrait for MyStruct {
fn do_stuff(&self) -> Result<i32, ExternalError> {
do_my_things()?;
Ok(200)
}
}
点击此处查看完整代码示例,但是这段代码无法编译:
error[E0277]: `?` couldn't convert the error to `external_module::ExternalError`
--> src/main.rs:28:23
|
28 | do_my_things()?;
| ^ the trait `std::convert::From<MyError>` is not implemented for `external_module::ExternalError`
|
= note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait
= note: required by `std::convert::From::from`
为了使其编译,我可以明确地使用
into()
: do_my_things().map_err(|e| e.into())?;
Playground。这里有两个问题:
- 为什么“?”操作符使用
From
而不是Into
?后者似乎更合理,因为它会更加宽容:From<A> for B
意味着Into<B> for A
,但反之不成立。 - 在我特定的情况下,处理错误转换的最佳方法是什么?编写
.map_err(|e| e.into())
看起来非常冗长(有时我甚至不得不在闭包中显式指定类型,因为编译器无法推断它们!)
一些背景信息:当我使用tonic库时遇到了这种情况。该库从.proto
文件生成trait,然后希望您实现它们(请参见基本的helloworld示例)。如果失败,则需要返回Err(tonic::Status)
,它基本上包含GRPC错误代码和错误消息。我不希望我的内部错误类型与GRPC错误代码有任何关系,我只想在我的错误转换为tonic::Status
时添加它们。
Into
,但是还有一个关于使用正确特质的部分,包括From
、Into
或其他内容。我找不到任何关于这个问题解决的参考资料,但是最初的实现最终使用了From
。 - mcarton