正如我认为的那样,正则表达式不会生存

时间:2016-06-23 13:26:12

标签: string reference rust lifetime

我试图编写一个带有正则表达式的Rust函数,以及一个字符串/ str并返回该正则表达式中所有已命名捕获的HashMap。这是代码:

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
}

我得到这个编译器错误(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);
        ...

但是,我不明白。在这种情况下,regex::Regex::captures return value has a lifetime of 't, which is the same lifetime as the string表示'a'regex::Captures::iter_named returned value also has the same lifetime of 't,在这种情况下为'a,这意味着(name, value) for that thing也应该是{{} 1}},在本例中为't

我的函数定义有一个使用'a生命周期的HashMap,所以不应该只使用Just Work(tm)吗?我想我明白为什么你不能使用局部变量,除非你退回它,但在这种情况下,我使用的引用应该足够长,对吗?

我想我可以'a .clone()的所有内容,但我很好奇我是否可以仅使用引用来编写此内容。那不应该更高效吗?我对Rust有点新意,所以我试图以适当,先进的方式处理事情并做事。

1 个答案:

答案 0 :(得分:2)

你的推理是正确的,但你忘记了一个细节:

  

regex::Regex::captures返回值的生命周期为't,这与字符串的生命周期相同,在本例中,这意味着'aregex::Captures::iter_named *返回值也具有't的相同生命周期,在这种情况下为'a,这意味着该事件的(name, value)也应为't,在本例中为'a { {1}}。

* regex::Captures::iter_named还需要&'t self,即&caps必须有生命周期't(在这种情况下为'a)。

请注意,编译器并未抱怨results,而是抱怨capsregex::Regex::captures会返回caps: Captures<'a>,这意味着上限会包含生命周期'a。但要致电regex::Captures::iter_named,必须使用生命周期'aiter_named参数为&'a self = &'a Captures<'a>)的引用。 虽然caps包含生命周期'a,但它没有生命周期'a (生命周期只是Some手臂。)

我不知道iter_named如何使用空名称处理捕获,但这是一个只返回命名捕获的实现:

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
}

这可能比iter_named慢。