2016-08-22 38 views
1

A是一種結構。它包含一個B(又名B的矢量)列表。 A實現了add_b方法,該方法在B的列表中添加B實例。 B結構包含一個閉包屬性f。如果我將一個B添加到add_b的向量中,那沒問題。如果我用add_b添加兩個向量,我得到一個錯誤,說兩個閉包是不同的。而且我不知道如何避免這個錯誤並修復我的代碼。這是一個有點難以解釋(約真的很抱歉,如果你想我可以編輯),這裏是一個小例子:預期關閉,發現不同的關閉

// 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"))); 
    |>      ^^^^^^^^^^^^^^^^^ 

尤其有用:

  • 沒有兩個瓶蓋,即便是相同的,有相同的類型

  • 考慮您的拳擊關閉和/或使用它作爲一個特質對象

我們可以完全移除式B進一步簡化你的榜樣。然後唯一的任務是保存一個關閉向量。正如編譯器告訴我們的,沒有兩個閉包具有相同的類型。但Vec是一個同類數據結構,這意味着它中的每個項目都具有相同的類型。

我們可以通過引入一個間接級別來解決這個限制。正如編譯器所暗示的,這可以通過特質對象或裝箱來完成(後一種包括第一種)。相應的類型應該是這樣的:

  • Vec<&Fn()>(參考特質對象)
  • Vec<Box<Fn()>>(特質對象在一個盒子)

在你的榜樣,你要自己全部關閉,因此正確的選擇是將所有封閉包裝起來,因爲Box<T>是擁有封裝,而引用只是借用東西。

+0

謝謝!僅供參考:我認爲我瞭解你寫的內容,現在修復我的代碼並不容易(我仍然是初學者)。我通過刪除'B'(ok,check)來簡化我的代碼,然後嘗試在struct聲明中添加'Vec >',然後在'add_b'中添加'Box :: new(...)',並且仍然具有相同的錯誤。不知道明白我錯過了什麼,我仍然需要挖掘。 –

+0

生鏽的遊樂場在這裏:http://play.integer32.com/?gist = 74fa771c562d30c541db54b2e8cf8ec8 –

+1

如果閉包實際上沒有從環境中捕獲任何變量,那麼可能是沒有價值的,那麼'fn()'是一個合適的類型並且不需要裝箱。 –