2014-12-05 124 views
3

我想要使用for循環遍歷函數的向量並在每個步驟執行每個函數。遍歷函數的向量

fn f1(i: i32) -> i32 { 
    i * 2 
} 

fn f2(i: i32) -> i32 { 
    i * 4 
} 

fn main() { 
    let mut arr: Vec<|i32| -> i32> = Vec::new(); 
    arr.push(f1); 
    arr.push(f2); 

    for f in arr.iter() { 
     println!("{}", f(1)); 
    } 
} 

f(1)已嘗試執行給出了這樣的錯誤:

error: expected function, found '&|i32| -> i32' 

我把功能載體猜測他們的類型發生突變,不再像一個正常功能。有沒有辦法將它改回來,還是我錯過了什麼?

+0

您能給出一個最小可重現的例子嗎?什麼是'f1'和'f2'? – 2014-12-05 09:12:53

+0

http://stackoverflow.com/questions/26301269/calling-closures-from-an-array-in-rust,但其答案不再有效(可能在關閉改革後)。 – 2014-12-05 09:13:12

+0

@MatthieuM。編輯 – AllTheTime 2014-12-05 09:17:34

回答

8

已更新爲Rust 1.x,答案的舊版本仍保留在編輯歷史記錄中。

從Rust 1.x開始,unboxed closures是語言中唯一的閉包,它們不需要再添加功能標記。而且,靜態函數可以很容易地轉換爲無箱閉包。因此,調用函數從功能的載體正確的方法是:

fn f1(i: i32) -> i32 { i * 2 } 

fn f2(i: i32) -> i32 { i * 4 } 

fn main() { 
    let p1 = &f1; 
    let p2 = &f2; 
    let mut arr: Vec<&Fn(i32) -> i32> = Vec::new(); 
    arr.push(p1); 
    arr.push(p2); 

    for f in &arr { 
     println!("{}", (*f)(1)); 
    } 
} 

有與舊版本相同的代碼的一些差異,最顯着之處在於p1p2被矢量之前定義。這是必要的,因爲否則它可能暫時包含對已銷燬對象的引用。

這裏我已經使用了Fn()閉包,它可以通過共享引用訪問它的環境,所以通過引用迭代向量就足夠了。如果我已經使用了FnMut()閉包,我將不得不使用可變引用的迭代,類似的情況適用於FnOnce()並按值重複(儘管我認爲在後一種情況下不可能使用FnOnce(),因爲您可以' t存儲沒有裝箱的特質對象,並且Box<FnOnce()>現在不能被調用,需要像FnBox()這樣的解決方法)。

或者,如果你知道你只有靜態功能的工作,有可能指針直接對它們進行存儲,而無需使用封閉性狀:

fn f1(i: i32) -> i32 { i * 2 } 

fn f2(i: i32) -> i32 { i * 4 } 

fn main() { 
    let mut arr: Vec<fn(i32) -> i32> = Vec::new(); 
    arr.push(f1); 
    arr.push(f2); 

    for f in &arr { 
     println!("{}", (*f)(1)); 
    } 
} 

雖然f1f2實際上有不同的不兼容的類型,他們在適當的上下文中使用時會自動強制爲通用函數指針類型fn(i32) -> i32,如上例所示。

因爲靜態函數沒有任何環境,所以可以自由地克隆對它們的引用並通過任何引用來調用它們。如果你只需要靜態函數,這大概是的方法。

+0

你能稍微解釋一下,如何用'(* f)'推遲值使它可用嗎? – AllTheTime 2014-12-05 09:24:18

+0

沒有辦法在封閉簽名中指明它不會改變其環境嗎? – 2014-12-05 09:27:27

+0

@AllTheTime,'f'是'&mut | i32 | - > i32',所以得到'| i32 | - > i32',你必須解引用它,就像當你需要從'&int'獲得'int'一樣。 – 2014-12-05 09:28:48