2016-11-12 66 views
2

當我嘗試編譯此代碼(playground):借用過濾器關閉不活足夠長的時間

fn main() { 
    let iter = "abc123".chars().filter(&|&c: &char| c.is_digit(10)); 
    match iter.clone().take(3).count() { 
     3 => println!("{}", iter.collect::<String>()), 
     _ => {} 
    } 
} 

我收到以下錯誤:

error: borrowed value does not live long enough 
--> test.rs:2:41 
    | 
2 |  let iter = "abc123".chars().filter(&|c: &char| c.is_digit(10)); 
    |           ^^^^^^^^^^^^^^^^^^^^^^^^^ - temporary value only lives until here 
    |           | 
    |           temporary value created here 
... 
7 | } 
    | - temporary value needs to live until here 
    | 
    = note: consider using a `let` binding to increase its lifetime 

我明白,錯誤是有益告訴我要用let f = &|c: &char| c.is_digit(10);working code)在上面的行中宣佈關閉,但爲什麼這是必要的?

我也不確定爲什麼閉包必須包含兩個引用 - &|c: &char|。不是"abc123".chars()只是創建一個字符的迭代器?

+0

相關:http://stackoverflow.com/q/31374051/155423;附近的副本:http://stackoverflow.com/q/28776630/155423,http://stackoverflow.com/q/23969191/155423,[工作代碼](http://play.integer32.com/?gist=feb39ad6c2bd1641dcf463b65d560986&version =穩定); TL; DR:你可能想使用'by_ref'。 – Shepmaster

+0

@Shepmaster我想我想問的是如何克隆一個迭代器(在我被錯誤消息弄糊塗之前)。所以我怎麼做[this](例如https://play.rust-lang.org/?gist=a8f4f33423f100f857ffe2ce4f0263a8&version=stable&backtrace=0)(我知道這不是最好的辦法)。 – gib

回答

5

but why exactly is this necessary?

我真的不知道該如何解釋它比錯誤消息要好得多:

temporary value only lives until here 
temporary value created here 

您正在創建一個臨時值在一份聲明中(蓋子本身),然後取一個參考到它。當陳述結束時,價值被破壞 - 沒有東西擁有它!問題是代碼試圖保持參考到現在被銷燬的值。如果編譯器允許這樣做,那麼當它使用該引用時,誰知道將訪問哪些隨機數據。

the closure has to contain two references

那麼,它不來。 filter(|c| c.is_digit(10))工作得很好;類型推斷允許c被自動鍵入爲&char&c僅模式匹配並自動取消引用該值。這是多餘的,因爲方法調用automatically dereference

更大的問題是,代碼試圖克隆包含關閉,你不能做一個迭代器(1234(善良,人拒絕問一個問題之前,搜索))。您選擇解決此問題的巧妙方法是將參考克隆到閉包,這很好。

問題循環回到引用聲明末尾被銷燬的內容。


如果目標是忽略所有的非數字字符,跳過第3位,然後收集的數字的休息,你可以使用Iterator::skip

let iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.skip(3).collect(); 
println!("{}", together); 

如果我們的目標是在只有前三位數字的情況下,只有在有三位數字的情況下,我纔會收集這些數字,然後檢查是否結束:

let mut iter = "abc123".chars().filter(|c| c.is_digit(10)); 
let together: String = iter.by_ref().take(3).collect(); 

if iter.next().is_none() { 
    println!("{}", together); 
} 

這使用Iterator::by_ref。代替消費迭代器,by_ref創建一個可變的引用。可變引用迭代器實現Iterator,所以調用takecollect工作正常。但是,當這些完成後,iter仍然有效。

+0

是的,對不起,發生了什麼是我最初有[this](https://play.rust-lang.org/?gist=080f87f21823940bb52e92bc55a1299c&version=stable&backtrace=0)之類的東西,但後來我用'&| c :&char |'試圖安撫編譯器。這只是我想要找到一個MCVE,我知道這不是最好的方式。 雖然這真的很有啓發! – gib