首页 文章

延长'for'变量的生命

提问于
浏览
2

当我在Rust 0.12.0中编译下面的代码时,我收到以下错误:

error: borrowed value does not live long enough
let _ = match re.captures(a_line.unwrap().as_slice()) {

如何延长a_line的生命周期以便将c1推送到vect1?

let vect = process_file(filename_ref);
...
fn process_file(filename: &str) -> Vec<&str> {

    let re = regex!(r"^(\w+)\t(\w+)\t(\w+)\t(\w+)\n$");
    let mut vect1 = Vec::new();

    let filepath = Path::new(filename);
    let _ = match File::open(&filepath) {
        Ok(f) => {
            let mut filebuffer = BufferedReader::new(f);
            for a_line in filebuffer.lines() {
                let _ = match re.captures(a_line.unwrap().as_slice()) {
                    Some(c) =>  {
                        let c1 = c.at(1);
                        vect1.push(c1);
                        ...
                    },
                   ...
               };
           } // end for
       },
       Err(e) => println!("Error: {}", e)
   };

   return vect1;

}

1 回答

  • 3

    简短的回答是,不,你不能只是'延长'这样的变量的生命周期 .

    这是一个连接类型的游戏:

    • .lines返回Lines实例,即 Iterator<IoResult<String>> .

    • a_lineIoResult <String> = Result<String, IoError> ,因此.unwrap返回 String

    • .as_slice给出了字符串数据的非拥有视图,通过引用上的 'a 生命周期,静态限制为仅在 String 存在时可用,避免了在C中悬空引用和使用后的问题(更多信息)关于 String&strthis answerthe strings guide) .

    • .captures带有一些生命周期的 &str't )并尝试返回持续时间长的Captures . 在这种情况下, &str 的生命周期是 a_line 的生命周期 a_line ,因此 c 是一个 Captures 存储数据,只有这么长时间有效 .

    • .at返回 &strCaptures 存储的数据的 't 生命周期,也就是说,返回的 &str 只能保证持久,只要原始 &str 输入 captures (不能超过原始的多长时间) String 存在,因为它正在管理内存中的文本)

    因此, c1 只持续 a_linea_line 一样长,并且 String 在循环中作用域,也就是说,每次单步执行循环时,都会得到一个新的 String ,它在最后被解除分配 . 如果编译器允许它被放置在 vect1 中而使它逃脱,那么代码将容易使用 - 释放后/悬空参考存储器安全漏洞,因为每次迭代结束时都会释放 String 每个 &str 点(例如, return vect1vect1 中的 &str 将指向垃圾 .

    要解决这个问题,你需要削减内存依赖性:目前 &str 不能控制自己的内存,因此依赖于"parent" String 正确放置 . 相反,你可以让矢量内容控制自己的命运(好吧,记忆),使它们成为完全成熟的,例如, vect1.push(c1.to_string()) . 这将使 vect1 成为 Vec<String> ,然后这些值与循环内的 a_line 值之间不再存在连接 . 然后可以在不影响 vect1 内容的情况下尽可能多地释放/修改/传播该变量 .

相关问题