2015-04-06 16 views
5

Ich beginne mit Rust, und ich spiele mit der regex Kiste, damit ich einen Lexer erstellen kann.Iteratoren, Faulheit und Besitz

Der Lexer verwendet einen großen regulären Ausdruck, der eine Reihe von benannten Capture-Gruppen enthält. Ich versuche, die Ergebnisse meiner regulären Ausdruck zu nehmen und eine Vec<&str, &str> des Capture-Namen und Capture-Wert zu erstellen, aber ich laufe ständig in Frage bezüglich der Lebensdauer der Werte von Iteration beim Mappen und Filtern über die Ergebnisse zurückgegeben.

Ich denke, das hat etwas mit Faulheit zu tun und die Tatsache, dass der Iterator nicht verbraucht wurde, wenn aus dem Rahmen fallen, aber ich bin mir nicht sicher, wie das Problem tatsächlich zu lösen.

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); 
    } 
} 

Ausführen der obigen Code führt zu folgendem Fehler:

$ 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`. 

Antwort

7

Der Grenzpunkt in Ihrer Situation ist die .iter_named() Methode:

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

Notiere die &'t self: die Lebensdauer der Die Ausgabe wird an die Lebensdauer der Captures Instanz gebunden. Dies liegt daran, dass die Namen im Objekt Capture gespeichert sind, so dass alle &str dieses Objekt nicht überleben können.

Es gibt nur eine Lösung für das:

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(); 
: Sie können die Capture Instanzen am Leben halten müssen