2015-05-29 57 views
6

我想這個問題是關於總體生命期的,但是由於你不能寫出它們的類型,所以我在封閉時遇到了困難。如何聲明一個封閉的壽命比封閉塊更長

這個例子有點做作 - 我剛開始學習Rust,這是我一直在掛的。

該程序不會編譯:

fn main() { 
    let mut list: Vec<&Fn() -> i32> = Vec::new(); 

    { 
     list.push(&|| 1); 
    } 
} 

因爲:

src/main.rs:5:25: 5:24 error: borrowed value does not live long enough 
src/main.rs:5   list.push(&|| 1); 
           ^~~~ 
src/main.rs:2:50: 7:2 note: reference must be valid for the block suffix following statement 0 at 2:49... 
src/main.rs:2  let mut list: Vec<&Fn() -> i32> = Vec::new(); 
src/main.rs:3 
src/main.rs:4  { 
src/main.rs:5   list.push(&move || 1); 
src/main.rs:6  } 
src/main.rs:7 } 
src/main.rs:5:9: 5:26 note: ...but borrowed value is only valid for the statement at 5:8 
src/main.rs:5   list.push(&|| 1); 
         ^~~~~~~~~~~~~~~~~ 
src/main.rs:5:9: 5:26 help: consider using a `let` binding to increase its lifetime 
src/main.rs:5   list.push(&|| 1); 
         ^~~~~~~~~~~~~~~~~ 

我從這個錯誤中收集的是,封閉的壽命是有限的塊內的 聲明,但它需要爲main的整個主體生活。

我知道(或者,我認爲)通過關閉push作爲參考意味着push只是借用閉包,所有權將返回到塊。如果我可以將結果設爲push(即如果push取得了閉包的所有權),則此代碼可行,但由於閉包的大小不合適,我必須將其作爲參考傳遞給它。

是嗎?我怎樣才能使這個代碼工作?

回答

8

有你問兩兩件事:

  1. 指定的東西類型名不具有specifyable類型名稱
  2. 讓一個閉合的壽命比它的已定義塊。

第一個問題是通過不指定typename來解決的,並讓rust的類型推斷來完成工作。

let mut list: Vec<_> = Vec::new(); 

第二個問題是由不試圖使封活得更長,但通過使「按價值」這樣你就可以將它固定。這會強制您的閉包不引用任何內容,但擁有所有捕獲的值。

for i in 0..10 { 
    list.push(move || i); 
} 

現在,這給了我們一個新問題。如果我們向Vec添加不同的閉包,則類型將不匹配。因此,爲了實現這一點,我們需要關閉關閉。

fn main() { 
    let mut list: Vec<Box<Fn() -> i32>> = Vec::new(); 

    for i in 0..10 { 
     list.push(Box::new(move|| i)); 
    } 

    { 
     list.push(Box::new(move|| 42)); 
    } 
} 
6

借款不擁有他們指向的東西。你的問題是你借了一個臨時這是因爲你沒有將它存儲在任何地方,它會在借用後不再存在。如果有幫助,可以考慮借入不借貸價值,他們借存儲,臨時只有臨時存儲。

如果你想要借東西要持續任何特定的時間,你必須存儲,將持續至少,長期借款。在這種情況下,因爲您想要將借款存儲在Vec中,這意味着無論您從哪個存儲中借用,還是需要Vec以及。因此:

fn main() { 
    let closure; 
    let mut list: Vec<&Fn() -> i32> = Vec::new(); 

    { 
     closure = || 1; 
     list.push(&closure); 
    } 
} 

注意closure之前list定義是。在Rust中,數值在其範圍的末尾以反詞法順序被刪除,因此在list之後定義的所有變量必須在它之前被刪除,從而導致list包含無效指針。

如果你想推多個閉包,你將需要一個單獨的變量。

爲了避免可能的「我的實際問題不是這麼簡單」附錄(:P):f您需要返回list或以某種方式堅持它超越單個函數調用,請注意,是無法延期借款。在這種情況下,您需要做的是將list更改爲所有的,盒裝關閉(Vec<Box<Fn() -> i32>>)。