2016-08-22 9 views
1

Aは構造です。それはB(別名ベクトルB)のリストを含んでいます。 ABのリストにBインスタンスを追加するadd_bメソッドを実装しています。 B構造体にはクロージャープロパティfが含まれています。ベクトルadd_bBを1つ追加すればOKです。 add_bという2つのベクトルを追加すると、2つのクロージャが違うというエラーが表示されます。私はこのエラーを回避してコードを修正する方法を知らない。それは(そのことについては本当に申し訳ありません、あなたが望むなら、私は編集することができます)説明するのは少し難しいですが、ここでは最小限の例です。閉鎖が予想され、別の閉鎖を見つけた

// A struct... 
struct A<F> { 
    b_vec: Vec<B<F>> // A vector of B 
} 

// ...and it's implementation 
impl<F> A<F> where F: Fn() { 
    fn new() -> A<F> { 
     A { b_vec: Vec::new() } 
    } 

    fn add_b(&mut self, b: B<F>) { 
     self.b_vec.push(b); 
    } 
} 

// B struct... 
struct B<F> { 
    f: F 
} 

// ...and it's implementation 
impl<F> B<F> where F: Fn() { 
    fn new(f: F) -> B<F> { 
     B { f: f } 
    } 
} 

// I add two B (with their closures arguments) in A 
fn main() { 
    let mut a = A::new(); 
    a.add_b(B::new(|| println!("test"))); 
    a.add_b(B::new(|| println!("test2"))); 
} 

でこのコードの結果:

私は複数追加することができますどのように
error[E0308]: mismatched types 
    --> src/main.rs:29:22 
    | 
29 | a.add_b(B::new(|| println!("test2"))); 
    |     ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure 

は、 Bの異なるクロージャを使用していますAb_vec

答えて

4

それは常にフルコンパイラの出力を見てみる価値だ:

error: mismatched types [--explain E0308] 
    --> <anon>:33:22 
    |> 
33 |>  a.add_b(B::new(|| println!("test2"))); 
    |>      ^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure 
note: expected type `[[email protected]<anon>:32:22: 32:41]` 
note: found type `[[email protected]<anon>:33:22: 33:42]` 
note: no two closures, even if identical, have the same type 
    --> <anon>:33:22 
    |> 
33 |>  a.add_b(B::new(|| println!("test2"))); 
    |>      ^^^^^^^^^^^^^^^^^^^^ 
help: consider boxing your closure and/or using it as a trait object 
    --> <anon>:33:22 
    |> 
33 |>  a.add_b(B::new(|| println!("test2"))); 
    |>      ^^^^^^^^^^^^^^^^^ 

特に便利:

  • なし2つのクロージャを、同一でさえあれば、同じ型を持っている

  • は、我々は完全にタイプBを除去することにより、さらにあなたの例を簡素化することができますあなたの閉鎖をボクシングおよび/または形質オブジェクトとして

を、それを使用することを検討してください。次に、クロージャのベクトルを保存するだけです。コンパイラからわかるように、2つのクロージャの型は同じではありません。しかし、Vecは、同種のデータ構造です。つまり、その中のすべてのアイテムが同じタイプです。

この制限を回避するには、1レベルの間接を導入します。コンパイラが示唆するように、これは特性オブジェクトまたはボクシング(後者は最初のものを含む)のいずれかによって行うことができます。対応するタイプは、次のようになります。

  • Vec<&Fn()>あなたは自身すべて閉鎖したいあなたの例では(参照オブジェクトを形質に)
  • Vec<Box<Fn()>>(ボックス内の形質オブジェクト)

、したがって、正しい選択は、Box<T>が所有ラッパーであるため、すべてのクロージャをボックスすることです。ただし、参照はモノを借りるだけです。

+0

ありがとうございます!参考:あなたが書いたことを理解していると思います。コードを修正するのは簡単ではありません(私はまだ初心者です)。私は 'B'(ok、check)を削除してコードを簡略化し、構造体宣言に' Vec > 'を追加しようとした後、' add_b'に 'Box :: new(...)'を追加しても同じエラー。私が逃したものを理解していない、私はまだ掘る必要があります。 –

+0

ここで錆びた遊び場:http://play.integer32.com/?gist = 74fa771c562d30c541db54b2e8cf8ec8 –

+1

クロージャが実際に環境変数を取得しない場合、 'fn()'は適切な型であり、ボクシングする必要はありません。 –