2015-04-06 76 views
5

我開始使用Rust,我正在玩regex箱子,以便我可以創建一個詞法分析器。迭代器,懶惰和所有權

詞法分析器使用包含一堆命名捕獲組的大正則表達式。我試圖獲取正則表達式的結果,並創建捕獲名稱和捕獲值的Vec<&str, &str>,但是在映射和過濾結果時,從迭代返回的值的生存期一直存在問題。

我認爲這與懶惰有關,而且事實上迭代器在超出範圍時沒有被使用,但我不確定如何真正解決問題。

extern crate regex; 

use regex::Regex; 

fn main() { 
    // Define a regular expression with a bunch of named capture groups 
    let expr = "((?P<num>[0-9]+)|(?P<str>[a-zA-Z]+))"; 
    let text = "0ab123cd"; 
    let re = Regex::new(&expr).unwrap(); 

    let tokens: Vec<(&str, &str)> = re.captures_iter(text) 
     .flat_map(|t| t.iter_named()) 
     .filter(|t| t.1.is_some()) 
     .map(|t| (t.0, t.1.unwrap())) 
     .collect(); 

    for token in tokens { 
     println!("{:?}", token); 
    } 
} 

運行上面的代碼產生以下錯誤:

$ cargo run 
Compiling hello_world v0.0.1 (file:///Users/dowling/projects/rust_hello_world) 

src/main.rs:14:23: 14:24 error: `t` does not live long enough 
src/main.rs:14   .flat_map(|t| t.iter_named()) 
            ^
src/main.rs:17:19: 22:2 note: reference must be valid for the block suffix following statement 3 at 17:18... 
src/main.rs:17   .collect(); 
src/main.rs:18 
src/main.rs:19  for token in tokens { 
src/main.rs:20   println!("{:?}", token); 
src/main.rs:21  } 
src/main.rs:22 } 
src/main.rs:14:23: 14:37 note: ...but borrowed value is only valid for the block at 14:22 
src/main.rs:14   .flat_map(|t| t.iter_named()) 
            ^~~~~~~~~~~~~~ 
error: aborting due to previous error 
Could not compile `hello_world`. 

回答

7

在您的情況的極限點是.iter_named()方法:

fn iter_named(&'t self) -> SubCapturesNamed<'t> 

注意&'t self:的壽命輸出將被綁定到Captures實例的生命週期。這是因爲名稱存儲在Capture對象中,所以對它們的任何&str都不能超過此對象。

只有一個用於修復:你必須保持Capture實例活着:

let captures = re.captures_iter(text).collect::<Vec<_>>(); 
let tokens: Vec<(&str, &str)> = captures.iter() 
    .flat_map(|t| t.iter_named()) 
    .filter(|t| t.1.is_some()) 
    .map(|t| (t.0, t.1.unwrap())) 
    .collect();