更新于2015年5月16日:原问题中的代码适用于旧版本的Rust,但概念仍然相同。本答案已更新为使用现代Rust语法/库(基本上将~[]
更改为Vec
,将~str
更改为String
并调整示例代码)。
我的理解大致准确吗?
[...]
在上面的示例中,类型为&str的参数和类型为&'a str的参数之间有什么区别?
是的,像那样的生命周期本质上表示“没有限制”,有点像。生命周期是将输出值与输入连接起来的一种方式,即fn foo<'a, T>(t: &'a T) -> &'a T
表示foo
返回具有与t
相同生命周期的指针,也就是说,它所指向的数据在与t
相同的时间长度内有效(严格地说,至少是这样)。这基本上意味着返回值指向t
指向的某些内存子部分。
所以,像
fn<'a>(path: &'a str) -> Vec<String>
这样的函数与写
{ let x = 1; return 2; }
非常相似...它是一个未使用的变量。
Rust在编写&str
时分配默认生命周期,这与编写未使用变量的生命周期完全相同。即fn(path: &str) -> Vec<String>
与带有'a
的版本没有区别。仅当省略生命周期与包括它时不同的时间是,如果您需要强制执行全局指针(即特殊的'static
生命周期),或者如果要返回引用(例如-> &str
),则仅当返回值具有生命周期时才可能(并且必须是一个或多个输入的寿命,或'static
)。
什么是生命周期?我在哪里可以了解更多关于它们的信息?
一生命周期是指指针所指向的数据存在的保证时间,例如全局变量被保证会持续“永远”(因此它有特殊的生命周期
'static
)。一个巧妙的看待它们的方式是:生命周期将数据连接到其所有者所在的堆栈帧上;一旦该堆栈帧退出,所有者就会超出范围,任何指向/进入该值/数据结构的指针都不再有效,生命周期是编译器推理此事的一种方式。(使用堆栈帧视图,就好像
@
与当前任务关联了一个特殊的堆栈帧,而
static
则有一个“全局”堆栈帧)。
书中还有一个
lifetimes chapter of the book,而
this gist(注意,代码已过时,但概念仍然正确)是一个巧妙的小演示,展示了如何使用生命周期来避免复制/分配(具有强大的安全保证:没有悬空指针的可能性)。
顺便问一下,什么是'self
?
字面上并没有什么特别的,只是某些地方需要类型具有生命周期(例如在结构/枚举定义和impl中),目前仅接受
'self
和
'static
这两个名称。
'static
用于全局始终有效的指针,
'self
用于可以拥有任何生命周期的内容。将非
static
的生命周期命名为除
self
以外的其他名称是一个错误。
总的来说,我会这样编写那个函数:
use std::fs::File;
use std::io::prelude::*;
use std::io::BufReader;
use std::path::Path;
fn read_file_lines(path: &Path) -> Vec<String> {
match File::open(path) {
Ok(file) => {
let read = BufReader::new(file);
read.lines().map(|x| x.unwrap()).collect()
}
Err(e) => panic!("Error reading file: {}", e)
}
}
fn main() {
let lines = read_file_lines(Path::new("foo/bar.txt"));
}
"data.txt"
的类型是&'static str
,它是一个静态分配的字符串。 - barjak