rust - 我怎样才能实现`从?`
问题描述
我正在编写一个新的板条箱,我希望它可用于任何特性的实现(在另一个板条箱中定义)。特征看起来像这样:
pub trait Trait {
type Error;
...
}
我有自己的Error
类型,但有时我只想转发未修改的底层错误。我的直觉是定义这样的类型:
pub enum Error<T: Trait> {
TraitError(T::Error),
...
}
这类似于thiserror鼓励的模式,并且似乎是惯用的。它工作正常,但我也想?
在我的实现中使用,所以我需要实现From
:
impl<T: Trait> From<T::Error> for Error<T> {
fn from(e: T::Error) -> Self { Self::TraitError(e) }
}
那失败了,因为它与impl<T> core::convert::From<T> for T
. 我想我明白为什么——其他一些实现者Trait
可以设置type Error = my_crate::Error
两个impl
s 都适用——但是我还能如何实现类似的语义呢?
我查看了其他一些 crate,它们似乎通过使它们的Error
(或等效的)泛型而不是错误类型本身而不是 trait 实现来处理这个问题。当然,这可行,但是:
- 在我们拥有固有的关联类型之前,它会更加冗长。我
T
实际上实现了多个特征,每个特征都有自己的Error
类型,所以我现在必须返回诸如Result<..., Error<<T as TraitA>::Error, <T as TraitB>::Error>>
etc 之类的类型; - 可以说它的表现力较差(因为与 to 的关系
Trait
丢失了)。
使我Error
对单个类型的泛型成为当今最好的(最惯用的)选择吗?
解决方案
不要From
为您的Error
枚举实现,而是考虑Result::map_err
结合使用?
来指定要返回的变体。这甚至适用于使用关联类型的类型上的泛型枚举,例如:
trait TraitA {
type Error;
fn do_stuff(&self) -> Result<(), Self::Error>;
}
trait TraitB {
type Error;
fn do_other_stuff(&self) -> Result<(), Self::Error>;
}
enum Error<T: TraitA + TraitB> {
DoStuff(<T as TraitA>::Error),
DoOtherStuff(<T as TraitB>::Error),
}
fn my_function<T: TraitA + TraitB>(t: T) -> Result<(), Error<T>> {
t.do_stuff().map_err(Error::DoStuff)?;
t.do_other_stuff().map_err(Error::DoOtherStuff)?;
Ok(())
}
这里重要的位是Error
没有From
实现(除了一揽子的),并且变体是使用map_err
. 这Error::DoStuff
可以解释为fn(<T as TraitA>::Error) -> Error
当传递给时map_err
。也一样Error::DoOtherStuff
。
这种方法是可扩展的,无论有多少变体Error
以及它们是否是同一类型。阅读函数的人也可能更清楚,因为他们可以找出某个错误来自某个地方,而无需检查From
实现以及被转换的类型出现在函数中的位置。
推荐阅读
- java - 操作栏和片段之间的空行
- mysql - MYSQL查询各种版本的常见bug
- c# - 使用 Asp .Net MVC 的 Google 两因素身份验证
- c++ - 比较两个没有共同行的大文件
- c++ - 是否有可能使用 debug_info 获取 ELF 文件的源代码?
- amazon-s3 - 如何在 AWS Amplify Storage.get API 函数中获取永不过期的 URL?
- c# - 使用 Firebase 匿名登录时,ProviderData 为空
- google-cloud-platform - 模板化数据流中的 Pub/Sub 输入完全忽略 NestedValueProvider
- javascript - 如何使用正则表达式在 div 类中获取段落
- mongoose - 如何使用 GraphQL 和猫鼬将文件从客户端上传到数据库?