字符串 – 正如我认为的那样,正则表达式捕获不会存在

我正在尝试编写一个带有正则表达式和字符串/ str的Rust函数,并返回该正则表达式中所有已命名捕获的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也应该是’t,在这种情况下是’a.

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

我想我可以.clone()把所有东西都变成String,但我很好奇我是否可以用引用来编写它.那不应该更高效吗?我对Rust有点新意,所以我试图以适当,先进的方式处理事情并做事.

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

regex::Regex::captures return value has a lifetime of 't, which is the same lifetime as the string, in this case, that means 'a, the regex::Captures::iter_named* returned value also has the same lifetime of 't, which is 'a in this case, and that means the (name, value) for that thing should also be 't, which in this case is 'a.

* regex :: Captures :: iter_named也需要一个自我,也就是说,& caps必须有生命周期’t'(在这种情况下为’a).

请注意,编译器不是抱怨结果而是抱怨大写. regex :: Regex :: capture返回上限:Captures<‘a&gt ;,这意味着上限保留了一些生命周期’a.但是要调用regex :: Captures :: iter_named,必须有一个带有生命周期’的参考(iter_named参数是&’a self =&’a Captures<‘a>).虽然大写字母持有生命周期’a’,但它没有生命周期’a(生命周期只有Some arm).

我不知道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慢.

点赞