为了账号安全,请及时绑定邮箱和手机立即绑定

使用泛型类型时,如何实现“From”的冲突?

使用泛型类型时,如何实现“From”的冲突?

我正在尝试实现一个错误枚举,它可能包含与我们的某个特征相关的错误,如下所示:trait Storage {     type Error;}enum MyError<S: Storage> {     StorageProblem(S::Error),}我还试图实现From特性以允许MyError从一个实例构建Storage::Error:impl<S: Storage> From<S::Error> for MyError<S> {     fn from(error: S::Error) -> MyError<S> {         MyError::StorageProblem(error)     }}但是这无法编译:error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`:  --> src/lib.rs:9:1   | 9 | impl<S: Storage> From<S::Error> for MyError<S> {   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^   |   = note: conflicting implementation in crate `core`:           - impl<T> std::convert::From<T> for T;我不明白为什么编译器认为这已经实现了。错误消息告诉我已经有一个From<MyError<_>>(有)的实现,但我不想在这里实现 - 我正在尝试实现,From<S::Error>并且MyError与S::Error我所看到的类型不同。我是否遗漏了仿制药的基本内容?使用泛型类型时,如何实现“From”的冲突?
查看完整描述

2 回答

?
小唯快跑啊

TA贡献1863条经验 获得超2个赞

这里的问题是有人可能会实现,Storage以便From你写的impl与标准库中的impl重叠impl<T> From<T> for T(也就是说,任何东西都可以转换为自身)。

特别,

struct Tricky;impl Storage for Tricky {
    type Error = MyError<Tricky>;}

(这里的设置意味着这实际上不是编译 - MyError<Tricky>无限大 - 但该错误与关于impls / coherence /重叠的推理无关,实际上小的改变MyError可以使其编译而不改变基本问题,例如添加一个BoxStorageProblem(Box<S::Error>),。)

如果我们用你的impl Tricky代替S,我们得到:

impl From<MyError<Tricky>> for MyError<Tricky> {
    ...}

impl与使用T== 的自转换完全匹配MyError<Tricky>,因此编译器不知道选择哪一个。Rust编译器避免了这样的情况,而不是进行任意/随机选择,因此必须拒绝原始代码,因为存在这种风险。

这种一致性限制肯定会令人烦恼,并且是专业化是一个备受期待的特性的原因之一:本质上允许手动指示编译器如何处理重叠......至少,当前受限形式的扩展之一允许这样做。


查看完整回答
反对 回复 2019-08-28
?
繁星淼淼

TA贡献1775条经验 获得超11个赞

一致性问题的解决方法是使用Result::map_err自己执行转换。然后,您可以使用末尾Result带有try!?

fn example<S: Storage>(s: S) -> Result<i32, MyError<S>> {
    s.do_a_thing().map_err(MyError::StorageProblem)?;
    Ok(42)}

当存在具有相同底层的错误变体时,此解决方案也很有用Error,例如,如果要分离“文件打开”和“文件读取”错误,两者都是io::Error


查看完整回答
反对 回复 2019-08-28
  • 2 回答
  • 0 关注
  • 512 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信