【问题标题】:Regex captures don't live as long as I think they should正则表达式捕获不会像我认为的那样长寿
【发布时间】:2016-06-23 13:26:12
【问题描述】:

我正在尝试编写一个 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,它使用'a 的生命周期,所以不应该是Just Work(tm) 吗?我想我理解为什么你不能使用局部变量,除非你返回它,但在这种情况下,我使用的引用应该足够长,对吧?

我想我可以将.clone() 的所有内容都发送到String,但我很好奇我是否可以仅使用参考来编写此内容。那不是应该更有效率吗?我对 Rust 有点陌生,所以我正在尝试以一种正确、先进的方式去探索和做事。

【问题讨论】:

    标签: string reference rust lifetime


    【解决方案1】:

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

    regex::Regex::captures返回值的生命周期为't,与字符串的生命周期相同,在这种情况下,即'aregex::Captures::iter_named*返回值的生命周期也与@987654326相同@,在这种情况下是'a,这意味着那个东西的(name, value)也应该是't,在这种情况下是'a

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

    请注意,编译器不是在抱怨results,而是在抱怨capsregex::Regex::captures 返回 caps: Captures&lt;'a&gt;,这意味着 caps 拥有生命周期 'a 的东西。但是要调用regex::Captures::iter_named,必须有一个生命周期'a 的引用(iter_named 参数是&amp;'a self = &amp;'a Captures&lt;'a&gt;)。 虽然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 慢。

    【讨论】:

    • > regex::Captures::iter_named 还需要&amp;'t self,即&amp;caps 必须有生命周期't ('a)。但是the captures function 应该返回一些生命周期为't 的东西,对吧?
    • 你可能没有完全回答我关于生命周期的问题,但你已经解决了根本问题。 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-24
    • 2014-01-02
    • 2013-05-25
    • 2016-06-04
    • 2011-09-08
    • 1970-01-01
    相关资源
    最近更新 更多