2016-12-11 35 views
2

我想在魯斯特創建這樣一個結構:閉包作爲防鏽結構型

pub struct Struct<T, F> 
    where T: Eq, 
      T: Hash, 
      F: Fn() -> T 
{ 
    hashMap: HashMap<T, F>, 
    value: T, 
} 

我的構造是這樣的:

pub fn new(init_value: T) -> Struct<T, F> { 
    Struct { 
     hashMap: HashMap::new(), 
     value: init_state, 
    } 
} 

但是試圖將類實例時,使用let a = Struct::<MyEnum>::new(MyEnum::Init);,編譯器抱怨泛型需要兩個參數(expected 2 type arguments, found 1

我看到了here這段代碼的工作原理:

fn call_with_one<F>(some_closure: F) -> i32 
    where F: Fn(i32) -> i32 { 

    some_closure(1) 
} 

let answer = call_with_one(|x| x + 2); 

我想問題來自我在我的模板實例中有另一個泛型,但我該怎麼做?

回答

6

Struct::new沒有任何依賴於F的參數,所以編譯器無法推斷它應該用於F的類型。如果以後調用了使用F的方法,那麼編譯器將使用該信息來計算Struct的具體類型。例如:

use std::hash::Hash; 
use std::collections::HashMap; 

pub struct Struct<T, F> 
    where T: Eq, 
      T: Hash, 
      F: Fn() -> T, 
{ 
    hash_map: HashMap<T, F>, 
    value: T, 
} 

impl<T, F> Struct<T, F> 
    where T: Eq, 
      T: Hash, 
      F: Fn() -> T, 
{ 
    pub fn new(init_value: T) -> Struct<T, F> { 
     Struct { 
      hash_map: HashMap::new(), 
      value: init_value, 
     } 
    } 

    pub fn set_fn(&mut self, value: T, func: F) { 
     self.hash_map.insert(value, func); 
    } 
} 

fn main() { 
    let mut a = Struct::new(0); 
    a.set_fn(0, || 1); // the closure here provides the type for `F` 
} 

雖然這存在問題。如果我們調用set_fn第二次用不同的封閉:

fn main() { 
    let mut a = Struct::new(0); 
    a.set_fn(0, || 1); 
    a.set_fn(1, || 2); 
} 

那麼我們得到一個編譯錯誤:

error[E0308]: mismatched types 
    --> <anon>:33:17 
    | 
33 |  a.set_fn(1, || 2); 
    |     ^^^^ expected closure, found a different closure 
    | 
    = note: expected type `[[email protected]<anon>:32:17: 32:21]` 
    = note: found type `[[email protected]<anon>:33:17: 33:21]` 
note: no two closures, even if identical, have the same type 
    --> <anon>:33:17 
    | 
33 |  a.set_fn(1, || 2); 
    |     ^^^^ 
help: consider boxing your closure and/or using it as a trait object 
    --> <anon>:33:17 
    | 
33 |  a.set_fn(1, || 2); 
    |     ^^^^ 

由於編譯器所提到的,每個封閉表達式定義一個全新的類型,計算結果爲那種類型。但是,通過定義Struct的方式,可以強制HashMap中的所有函數具有相同的類型。那真的是你想要的嗎?

如果您想將T的不同值映射到可能不同類型的閉包,那麼您需要使用trait對象而不是泛型,正如編譯器所建議的那樣。如果你想讓結構擁有閉包,那麼你必須圍繞對象類型使用Box

pub struct Struct<T> 
    where T: Eq, 
      T: Hash, 
{ 
    hash_map: HashMap<T, Box<Fn() -> T + 'static>>, 
    value: T, 
} 

set_fn然後可能看起來像這樣:

pub fn set_fn<F: Fn() -> T + 'static>(&mut self, value: T, func: F) { 
    self.hash_map.insert(value, Box::new(func)); 
} 
+0

謝謝!這確實解決了我的問題。我不明白'T +'靜態'語法。這是什麼(所以我可以閱讀適當的文檔)?這是關於一生的嗎? – pLesur

+0

這裏''static'是一個_lifetime bound_。它限制了實現'Fn() - > T'的類型中借用指針的生存期。 ''static'意味着這個類型不能包含任何短於''static'的借入指針(一個沒有借用指針的類型是OK的)。如果你需要更多的靈活性,你可以在'Struct'上引入一個生命週期參數('<'a, T>')並用它來代替。 –