2016-05-20 4 views
5

私はこのような当社の特徴の一つに関連したエラーを含むことができ、エラーの列挙型を実装しようとしています:ジェネリック型を使用しているときに `From`の実装がどのように矛盾していますか?

trait Storage { 
    type Error; 
} 

enum MyError<S: Storage> { 
    StorageProblem(S::Error), 
} 

私ものインスタンスからMyErrorの構築を可能にしFrom形質を実装しようとしていますStorage::Error

impl<S: Storage> From<S::Error> for MyError<S> { 
    fn from(error: S::Error) -> MyError<S> { 
     MyError::StorageProblem(error) 
    } 
} 

playground

しかし、これはコンパイルに失敗します。

error[E0119]: conflicting implementations of trait `std::convert::From<MyError<_>>` for type `MyError<_>`: 
    --> src/main.rs:9:1 
    | 
9 |/impl<S: Storage> From<S::Error> for MyError<S> { 
10 | |  fn from(error: S::Error) -> MyError<S> { 
11 | |   MyError::StorageProblem(error) 
12 | |  } 
13 | | } 
    | |_^ 
    | 
    = note: conflicting implementation in crate `core` 

コンパイラがこれを既に実装している理由がわかりません。エラーメッセージは、すでに実装されているFrom<MyError<_>>(これがあります)ですが、実装しようとしていません - 実装しようとしていますFrom<S::Error>MyErrorは同じタイプではありませんS::Error見る。

ここにジェネリックスの基本的なものがありませんか?

答えて

8

ここでの問題は、あなたが書かれているIMPL Fromimpl<T> From<T> for Tの標準ライブラリでIMPLと重なっていること(つまり、何が自分自身に変換することができます)ので、誰かがStorageを実装することです。

すなわち、

struct Tricky; 

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

は、(セットアップここでは、これは実際— MyError<Tricky>をコンパイルしないことを意味無限大—であるが、エラーが実際impl S /コヒーレンス/オーバーラップについての推論とは無関係であり、そしてStorageProblem(Box<S::Error>),ようBoxを追加する小さなMyErrorへの変更、それは根本的な問題を変更せずにコンパイルすることができ、例えば。)

我々は、0の代わりにTrickyに置き換えた場合独自の実装では、我々が得る:

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

このimplはまさにT == MyError<Tricky>で自己変換1と一致し、したがって、コンパイラが選択するかを知ることはできません。 Rustコンパイラは、任意の/ランダムな選択をする代わりに、このような状況を回避します。したがって、このリスクのために元のコードを拒否する必要があります。

specialisationは、非常に期待される機能です。本質的には、手動でオーバーラップを処理する方法をコンパイラに指示することができます...少なくともone of the extensionsは現在の制限付きフォームに対応しています。

+0

夜間に拡張機能が実装されましたか? – WiSaGaN

+0

いいえ、実際には制限されたフォームは引き続き夜間にのみ利用できます。私は、より柔軟でパワフルなバージョンにダイビングする前に、バグをビット/アイロンでベーキングすることを意図していると信じています。 – huon

+0

明確な答え:ありがとう。私は、エラーメッセージが、既にそこにあることを暗示するのではなく、実装が矛盾しているかもしれないと言った場合、少しはっきりするかもしれないと思います。 – Fraser

1

コヒーレンスの問題を回避するには、Result::map_errを使用して自分で変換を実行します。その後、try!または?で終わりResultを使用することができます。

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

、そのようなあなたは、「ファイルを開く」と「ファイルを分離する場合と同じ基本的なErrorを持つエラー変異体は、存在する場合に、このソリューションは貴重です読み取りエラー "と呼ばれ、いずれもio::Errorである。

関連する問題