在铁锈的生活时间

偶尔我发现自己想要编写可以通过以下两种方式调用的函数:

// With a string literal: let lines = read_file_lines("data.txt"); // With a string pointer: let file_name = ~"data.txt"; let lines = read_file_lines(file_name); 

我的第一个猜测是使用借用指针( &str )作为参数types,但是当它不工作(它只允许我使用@str@str )时,我尝试了下面的方法(通过复制Rust库)哪些工作。

 fn read_file_lines<'a>(path: &'a str) -> ~[~str] { let read_result = file_reader(~Path(path)); match read_result { Ok(file) => file.read_lines(), Err(e) => fail!(fmt!("Error reading file: %?", e)) } } 

问题是我不明白我在做什么。 从我可以收集(主要是编译器错误),我声明一个没有限制的生命周期,并用它来描述path参数(意味着任何生命周期可以作为parameter passing)。

所以:

  • 我的理解隐约准确吗?
  • 什么是一生? 我在哪里可以了解更多关于他们?
  • 在上面的例子中,types为&str的参数和types为&str的参数之间有什么区别?
  • 而当我在这里,什么是'self

(我使用Rust 0.7,如果它对答案有所不同)

更新2015-05-16 :原始问题中的代码应用于旧版本的Rust,但概念保持不变。 这个答案已被更新为使用现代Rust语法/库。 (本质上将~[]改为Vec~str改为String ,最后调整代码示例。

我的理解隐约准确吗?
[…]
在上面的例子中,types为&str的参数和types为&str的参数之间有什么区别?

是的,像这样的一生,基本上说“没有限制”,有点。 生命周期是将输出值与input连接起来的一种方式,也就是说, fn foo<'a, T>(t: &'a T) -> &'a T表示foo返回一个与t相同生命期的指针, ,它所指向的数据与t的时间长度一样有效(呃,严格的说,至less和¯一样长)。 这基本上意味着返回值指向t指向的内存的某个子节点。

所以,像fn<'a>(path: &'a str) -> Vec<String>函数与写{ let x = 1; return 2; } { let x = 1; return 2; } { let x = 1; return 2; } …这是一个未使用的variables。

当写入&str ,Rust会分配默认的生命周期,这完全等同于写入未使用的生命周期。 即fn(path: &str) -> Vec<String>'a s 'a的版本没有区别。 离开一辈子的唯一时间是不同的,包括它是如果你需要执行一个全局指针(即特殊的'static生命周期”),或者如果你想返回一个引用(例如-> &str )返回值有一个生命周期(这必须是一个或多个input的生命周期或'static )。

什么是一生? 我在哪里可以了解更多关于他们?

一个生命期是一个指针指向的数据保证存在多长时间,例如一个全局variables保证永远持续下去(所以它的特殊生命期'static )。 一个简单的方法来看待它们:有生之年将数据连接到其所有者所在的堆栈框架; 一旦堆栈帧退出,所有者超出范围,任何指向该值/数据结构的指针都不再有效,并且生命周期是编译器推理的一种方式。 (使用堆栈框架视图,就好像@有一个特殊的堆栈框架与当前任务相关联,而static堆栈框架则具有“全局”堆栈框架)。

这本书还有一个有生命的篇章 , 这个要点 (注意,代码现在已经过时了,但概念仍然是真实的)是一个简单的示范,说明如何使用生命周期来避免复制/分配(具有强大的安全性保证:不可能悬挂指针)。

而当我在这里,什么是'self

从字面上看,没有什么特别的地方,只是某些地方需要types来维持生命周期(例如在struct / enum defintions和impl s中),而目前唯一被接受的名称是'self'static ”。 对于全局总是有效的指针来说是'static对于可以有任何生命周期 这是一个错误,调用(非static )生命除self是一个错误。


总而言之,我会写这样的function:

 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")); // do things with lines }