2017-03-11 22 views
1

私は様々なファイル形式から特定のオブジェクトを読み込み/デコードする特性を作り出しています。この特性は、内側リーダーオブジェクトのための一般的なstd::io::Readクラスを有する。私はファイルを開き、それを使用する便利なfrom_filenameコンストラクタを作ろうとしています。しかし、私はそれを動作させるように見えることはできません。ファイル構造体は読み込みを実装するものとして見なされませんか?

use std::io::Read; 
use std::fs; 
use std::path::Path; 

trait MyObjectReader { 
    type R: Read; 

    fn new(Self::R) -> Self; 

    fn from_filename(filename: &str) -> Self where Self: Sized { 
     let open_file = fs::File::open(&Path::new(filename)).unwrap(); 
     Self::new(open_file) 
    } 

    // other methods will go here 
} 

そして、私はこのエラーを取得する:

rustc 1.15.1 (021bd294c 2017-02-08) 
error[E0308]: mismatched types 
    --> <anon>:14:19 
    | 
14 |   Self::new(open_file) 
    |     ^^^^^^^^^ expected associated type, found struct `std::fs::File` 
    | 
    = note: expected type `<Self as MyObjectReader>::R` 
    = note: found type `std::fs::File` 

私は.unwrap()は、ライブラリ内のサブパーで、私はそれを後で変更でしょうね

これはコードです。

std::fs::Filestd::io::Readを実装していないため、このエラーを理解できません。私の心にはうまくいくはずです。

+1

'File :: open(&Path :: new(filename))'は冗長です。 'File :: open(filename)'で十分です。 – Shepmaster

答えて

3

doesn't std::fs::File implement std::io::Read ?

はい。しかし、あなたの形質の導入を検討してください。

impl MyObjectReader for SomeReaderImpl { 
    type R = AnythingYouLike; 
    // .. etc 
} 

問題はRFileかもしれないが、それはないかもしれないということです。

use std::io::Read; 
use std::fs; 

trait MyObjectReader { 
    type R: Read; 

    fn new(Self::R) -> Self; 

    fn from_filename(filename: &str) -> Self where Self: Sized; 
} 

struct MyFileReader; 

impl MyObjectReader for MyFileReader { 
    type R = fs::File; 

    fn new(_: Self::R) -> Self { 
     MyFileReader 
    } 

    fn from_filename(filename: &str) -> Self 
     where Self: Sized 
    { 
     let open_file = fs::File::open(filename).unwrap(); 
     Self::new(open_file) 
    } 
} 
+0

この解決策の問題は、 'MyObjectReader :: R'が' File'(または何らかの形で 'File'から来る)型の' MyObjectReader'だけを実装できるようになりました。そうでなければ、必要な 'from_filenameあなたが 'パニック'なのか何かをしなければ、あなたのせいではありません。問題の声明が原因です。 – Shepmaster

+0

@Shepmasterはい。 'from_filename'を特性から外して、それを' MyFileReader'の通常のメソッドにするのはおそらくもっと意味があります。 –

1

ジェネリックタイプのインターフェイスのようではありません。

あなたのデフォルトの実装ではので、おそらくその実装はR間違いFileがある特定のインスタンスに行く必要があり、RFileであると仮定しています。境界はサブクラス化されません。

type R: Read Readを実装するタイプを意味するわけではありません。抽象クラスではありません。プレースホルダ/エイリアスによく似ています。それはを実装する特定のタイプを意味します。どんなタイプになるかはimplブロックでのみ定義されているので、ブロックはその時点でそれを知らないので、traitブロックはそれを知りません。

それを見て別の方法は言うことによってSelf(任意R: Read付き)from_filename戻り、それはReadのすべての実現のために働くことがあるが、あなたの実装が唯一Self<R=File>を返すことができるということです。

0

あなたがnew方法にあなたのジェネリックの場所を移動することも望むことがあります。

use std::io::Read; 
use std::fs::File; 

trait MyObjectReader { 
    fn new<R: Read>(R) -> Self; 

    fn from_filename(filename: &str) -> Self 
     where Self: Sized 
    { 
     let open_file = File::open(&filename).unwrap(); 
     Self::new(open_file) 
    } 
} 

これはnewは関係なく、形質の実装がどのように定義するかの、Readを実装する任意のタイプを取ることができることを言いますR。これは、現在表示されていない他のメソッドでも必要な場合に、関連タイプと組み合わせることができます。

use std::io::Read; 
use std::fs::File; 

trait MyObjectReader { 
    type R: Read; 

    fn new<R2: Read>(R2) -> Self; 

    fn from_filename(filename: &str) -> Self 
     where Self: Sized 
    { 
     let open_file = File::open(&filename).unwrap(); 
     Self::new(open_file) 
    } 

    fn something_else(&self) -> Self::R; 
} 
関連する問題