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