当我在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;
}
答案 0 :(得分:3)
简短的回答是,不,你不能只是扩展&#39;像这样的变量的生命周期。
这是一个连接类型的游戏:
.lines
返回Lines
个实例,即Iterator<IoResult<String>>
。a_line
是IoResult
<String> = Result<String, IoError>
,因此.unwrap
会返回String
.as_slice
提供字符串数据的非拥有视图,该数据通过引用的'a
生命周期,静态限制为仅在String
时可用存在避免在C ++中悬空引用和使用后免费的问题(更多关于String
与&str
的对比:this answer&amp; the strings guide)。.captures
需要&str
生命周期('t
)并尝试返回持续时间长的Captures
。在这种情况下,&str
的生命周期是String
中a_line
的生命周期,因此c
是Captures
只存储数据的&str
有效期很长。.at
返回't
,Captures
存储的数据的生命周期为&str
,也就是说,返回的&str
仅保证最后只要原始captures
投放到String
(这可能比原始c1
存在的时间长,因为它会在内存中管理文本)因此,String
只会持续a_line
String
的{{1}},并且String
的范围限定在循环中,也就是说,每次单步执行在循环中,您得到一个新的vect1
,它在最后被解除分配。如果编译器通过允许它放在String
中让它逃脱,代码将容易使用 - 释放后/悬空参考内存安全错误&str
每个&str
点在每次迭代结束时释放into(例如,vect1
行上的return vect1
中的所有&str
都指向垃圾。
要解决这个问题,你需要削减内存依赖性:目前String
s不能控制自己的内存,因此依赖于&#34; parent&#34; String
被正确放置。相反,你可以通过使它们成为完全成熟的vect1.push(c1.to_string())
来给矢量内容控制它自己的命运(好吧,记忆)。 vect1
。这将使Vec<String>
成为a_line
,然后这些值与循环内的vect1
值之间不再存在连接。然后可以在不影响{{1}}的内容的情况下尽可能多地释放/修改/传播该变量。