2017-06-18 28 views
0

我有一個恆定的形式定義的陣列,任何函數外:迭代查找,臨時值下降,同時仍然借

const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

我試圖使用find()方法位於Iterator,在爲了從一個基於謂詞的數組中提取單個元素:

VALUES.iter().find(|&&(name, _)| name == 'A'); 

在這種形式下,它工作正常。但是,我無法將找到的元素評估爲任何內容,因爲只要我嘗試創建綁定,嘗試綁定結果,根據文檔應該返回爲Option<T>

讓我們改變第二行是不工作:

const VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

fn main() { 
    let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
} 

Playground

人們會想到這個返回Option<T>作爲根據文檔,而是我回來編譯錯誤:

error: borrowed value does not live long enough 
--> src/main.rs:4:63 
    | 
4 |  let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
    |     ------ temporary value created here  ^temporary value dropped here while still borrowed 
5 | } 
    | - temporary value needs to live until here 
    | 
    = note: consider using a `let` binding to increase its lifetime 

我完全困惑;我確定我剛剛與「借閱檢查器」搞混了。也許有人可以指出我正確的方向?

回答

2

問題出在您將該數組轉換爲迭代器的特定方式。

首先,Rust中的const實際上並不存在於任何地方。相反,他們在任何地方都被價值取代。所以每次你使用一個常量,你都會得到一個新的副本。其次,你正在使用IntoIterator::into_iter。這需要的值並將其轉換爲迭代器。

這些結合第三部分:IntoIterator而不是實現了固定大小的數組。它只適用於指針固定大小的數組。因此,爲了調用into_iter,編譯器必須插入調用者的自動借用。

那麼,什麼是實際發生的情況是這樣的:

let t = { 
    // Make a new copy of `VALUES`. 
    let values: [(char, &str); 5] = VALUES; 
    // Borrow it. 
    let values: &[_] = &values; 
    // Call `into_iter` on the borrow. 
    IntoIterator::into_iter(values).find(|&&(name, _)| name == 'A') 
}; 

這會導致問題,因爲編譯器必須同時複製爲了得到一個迭代器借用VALUES。像所有臨時人員一樣,所述複製只在陳述時才存在,但借用(通過綁定到變量)必須比這更長壽。

最好的解決辦法是將VALUES一個指針給數組。這可以防止複製整個數組;相反,您只能在每次使用時複製指針。

const VALUES: &[(char, &str)] = &[...]; 

或者,你可以明確地做出VALUES副本,並將其存儲在一個變量,然後在使用into_iter。但是,像以前一樣,這會引入不必要的複製。

+0

Const數組實際存在於內存中。 [此代碼](https://play.rust-lang.org/?gist=023a4c4ea0cc8cac7a890bbd3a05d876&version=stable&backtrace=0)有效。被刪除的臨時值不是數組,而是數組片。 – red75prime

+1

@ red75prime:我的理解是*那*行爲是一種特殊情況,即立即借用的臨時對象被提升,因爲這種模式比較常見,否則會更加痛苦。 –

+0

另一種選擇是使用「靜態」,它存在於內存中,因此可以正常借用。 – zstewart

0

DK.'s answer是正確的,但我建議進行一個簡單的更改以使您的代碼正常工作 - 使用static而不是const

documentation about static and const

More specifically, constants in Rust have no fixed address in memory.

static items aren’t inlined upon use. This means that there is only one instance for each value, and it’s at a fixed location in memory.

切換到static可以讓你得到你迭代的事情內存地址。

static VALUES: [(char, &str); 2] = [('A', "abc"), ('B', "acb")]; 

fn main() { 
    let result = VALUES.iter().find(|&&(name, _)| name == 'A'); 
} 

這裏,resultOption<&(char, &str)>