2016-06-23 22 views
4

Ich versuche, eine Rust-Funktion zu schreiben, die eine Regex und eine Zeichenfolge/str und eine HashMap aller genannten Captures in dieser Regex zurückgibt. Hier ist der Code:Regex-Captures leben nicht so lange, wie ich denke, sie sollten

use std::collections::HashMap; 
use regex::Regex; 

fn get_matches<'a>(line: &'a str, re: &Regex) -> HashMap<&'a str, &'a str> { 
    let mut results = HashMap::new(); 

    match re.captures(line) { 
     None => { return results; }, 
     Some(caps) => { 
      for (name, value) in caps.iter_named() { 
       if let Some(value) = value { 
        results.insert(name, value); 
       } 
      } 
     } 
    } 

    results 
} 

Und ich bekomme diesen Compiler-Fehler (Rust 1.9.0):

error: `caps` does not live long enough 
     for (name, value) in caps.iter_named() { 
          ^~~~ 
note: reference must be valid for the lifetime 'a as defined on the block at 6:79... 
    fn get_matches<'a>(line: &'a str, re: &Regex) -> HashMap<&'a str, &'a str> { 
     let mut results = HashMap::new(); 

     match re.captures(line) { 
      None => { return results; }, 
      Some(caps) => { 
    ... 
note: ...but borrowed value is only valid for the match at 9:8 
     match re.captures(line) { 
      None => { return results; }, 
      Some(caps) => { 
       for (name, value) in caps.iter_named() { 
        if let Some(value) = value { 
         results.insert(name, value); 
     ... 

Allerdings verstehe ich nicht. regex::Regex::captures return value has a lifetime of 't, which is the same lifetime as the string, in diesem Fall, das heißt 'a' die regex::Captures::iter_named returned value also has the same lifetime of 't, die 'a ist in diesem Fall, und das bedeutet, die auch (name, value) for that thing't sein soll, die in diesem Fall 'a ist.

Meine Funktionsdefinition hat eine HashMap, die diese 'a Lebensdauer verwendet, sollte also nicht alles Just Work (tm)? Ich denke, ich verstehe, warum Sie eine lokale Variable nicht verwenden können, es sei denn, Sie geben es zurück, aber in diesem Fall verwende ich Referenzen, die lange genug leben sollten, oder?

Ich nehme an, ich könnte .clone() alles zu String, aber ich bin gespannt, ob ich dies mit nur Referenzen schreiben kann. Soll das nicht effizienter sein? Ich bin ein wenig neu in Rust, also versuche ich, Dinge zu verbessern und Dinge richtig zu machen.

Antwort

2

Ihre Argumentation ist richtig, aber Sie vergessen haben, ein Detail:

regex::Regex::captures Rückgabewert hat eine Lebensdauer von 't, die die gleiche Lebensdauer wie die Zeichenfolge ist, in diesem Fall die 'a bedeutet, die regex::Captures::iter_named * Rückgabewert hat auch die gleiche Lebensdauer von 't, die in diesem Fall 'a ist, und das bedeutet, dass die (name, value) für das Ding auch 't sein sollte, was in diesem Fall 'a ist.

* regex::Captures::iter_named erfordert auch eine &'t self, das heißt, &caps Lebensdauer 't ('a in diesem Fall) haben müssen.

Beachten Sie, dass der Compiler nicht über results, sondern über caps klagt. regex::Regex::captures gibt caps: Captures<'a> zurück, das bedeutet, dass Caps etwas mit Lebenszeit 'a enthält. Aber um regex::Captures::iter_named zu nennen, ist es notwendig, eine Referenz mit der Lebenszeit 'a zu haben (iter_named Parameter ist &'a self = &'a Captures<'a>). Obwohl caps etwas mit Lebensdauer 'a enthält, hat es keine Lebensdauer 'a (die Lebensdauer ist nur die Some Arm).


weiß ich nicht, wie iter_named Griff capture mit leeren Namen, aber hier ist eine Implementierung, die nur den Namen Captures zurück:

extern crate regex; 

use std::collections::HashMap; 
use regex::Regex; 

fn get_matches<'a>(line: &'a str, re: &'a Regex) -> HashMap<&'a str, &'a str> { 
    let mut results = HashMap::new(); 

    match re.captures(line) { 
     None => { 
      return results; 
     } 
     Some(caps) => { 
      for name in re.capture_names() { 
       if let Some(name) = name { 
        if let Some(value) = caps.name(name) { 
         results.insert(name, value); 
        } 
       } 
      } 
     } 
    } 

    results 
} 

Diese vielleicht langsamer als iter_named.

+0

> 'regex :: Captures :: iter_named' benötigt auch ein' & 't self ', dh' & caps' müssen lebenslange '' t' (' 'a') haben. Aber [die 'Captures'-Funktion] (https://doc.rust-lang.org/regex/regex/struct.Regex.html#method.captures) sollte etwas mit einer Lebensdauer von 't' zurückgeben, oder? – Rory

+0

@Rory Ich aktualisierte die Antwort. – malbarbo

+0

Sie haben vielleicht meine Antwort zu Lebenszeiten nicht beantwortet, aber Sie haben das zugrunde liegende Problem gelöst. :) – Rory