[英]Lifetimes in Rust
Occasionally I've found myself wanting to write functions that can be called in either of two ways: 偶尔我发现自己想要编写可以通过以下两种方式之一调用的函数:
// 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);
My first guess was to use a borrowed pointer ( &str
) for the parameter type, but when that didn't work (it only allowed me to use @str
and ~str
), I tried the following (by copying the Rust libraries), which did work. 我的第一个猜测是使用借用指针(
&str
)作为参数类型,但是当它不起作用时(它只允许我使用@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))
}
}
The problem is that I don't understand what I'm doing. 问题是我不明白我在做什么。 From what I can gather (mostly from compiler errors), I'm declaring a lifetime on which there is no restriction, and using it to describe the path parameter (meaning that any lifetime can be passed as the parameter).
从我可以收集的内容(主要来自编译器错误),我宣布一个没有限制的生命周期,并使用它来描述path参数(意味着任何生命周期都可以作为参数传递)。
So: 所以:
&str
and a parameter of type &'a str
in the example above? &str
的参数&'a str
上面示例中&'a str
类型的参数之间有什么区别? 'self
? 'self
? (I'm using Rust 0.7, if it makes a difference to the answer) (我正在使用Rust 0.7,如果它对答案有所影响)
Update 2015-05-16 : the code in the original question applied to an old version of Rust, but the concepts remain the same. 更新2015-05-16 :原始问题中的代码应用于旧版本的Rust,但概念保持不变。 This answer has been updated to use modern Rust syntax/libraries.
此答案已更新为使用现代Rust语法/库。 (Essentially changing
~[]
to Vec
and ~str
to String
and adjusting the code example at the end.) (本质上改变
~[]
至Vec
和~str
到String
和调整在端部的代码的例子。)
Is my understanding vaguely accurate?
我的理解是否模糊准确?
[...][...]
What is the difference between a parameter of type &str and a parameter of type &'a str in the example above?类型&str的参数和上面示例中&'str类型的参数之间有什么区别?
Yes, a lifetime like that says essentially "no restrictions", sort of. 是的,像这样的一生就基本上说“没有限制”。 Lifetimes are a way to connect output values with inputs, ie
fn foo<'a, T>(t: &'a T) -> &'a T
says that foo
returns a pointer that has the same lifetime as t
, that is, the data it points to is valid for the same length of time as t
(well, strictly, at least as long as). 生命周期是一种将输出值与输入连接起来的方法,即
fn foo<'a, T>(t: &'a T) -> &'a T
表示foo
返回一个与t
具有相同生命周期的指针,即,它指向的数据在与t
相同的时间长度内有效(严格地说,至少与此一样长)。 This basically implies that the return value points to some subsection of the memory that t
points to. 这基本上意味着返回值指向
t
指向的内存的某个子部分。
So, a function like fn<'a>(path: &'a str) -> Vec<String>
is very similar to writing { let x = 1; return 2; }
所以,像
fn<'a>(path: &'a str) -> Vec<String>
这样的函数fn<'a>(path: &'a str) -> Vec<String>
非常类似于写{ let x = 1; return 2; }
{ let x = 1; return 2; }
{ let x = 1; return 2; }
... it's an unused variable. { let x = 1; return 2; }
...这是一个未使用的变量。
Rust assigns default lifetimes when writing &str
, and this is exactly equivalent to writing the unused-variable lifetime. 在写
&str
,Rust会分配默认生命周期,这与编写未使用的变量生命周期完全相同。 ie fn(path: &str) -> Vec<String>
is no different to the version with 'a
s. 即
fn(path: &str) -> Vec<String>
与带有'a
s的版本没有区别。 The only time leaving off a lifetime is different to including it is if you need to enforce a global pointer (ie the special 'static
lifetime), or if you want to return a reference (eg -> &str
) which is only possible if the return value has a lifetime (and this must be either the lifetime of one-or-more of the inputs, or 'static
). 离开一生的唯一时间是不同的,包括它是否需要强制执行全局指针(即特殊的
'static
生命周期),或者如果你想返回一个引用(例如-> &str
),这只有在返回值有一个生命周期(这必须是一个或多个输入的生命周期,或'static
)。
What is a lifetime?
什么是一生? Where can I learn more about them?
我在哪里可以了解更多相关信息?
A lifetime is how long the data a pointer points to is guaranteed to exist, eg a global variable is guarantee to last "forever" (so it's got the special lifetime 'static
). 生命周期是指针指向的数据保证存在多长时间,例如全局变量保证持续“永久”(因此它具有特殊的生命周期
'static
)。 One neat way to look at them is: lifetimes connect data to the stack frame on which their owner is placed; 查看它们的一种巧妙方法是:生命周期将数据连接到其所有者所在的堆栈框架; once that stack frame exits, the owner goes out of scope and any pointers to/into that value/data-structure are no longer valid, and the lifetime is a way for the compiler to reason about this.
一旦该堆栈帧退出,所有者就会超出范围,并且任何指向/进入该值/数据结构的指针都不再有效,并且生命周期是编译器对此进行推理的一种方式。 (With the stack frame view, it is as if
@
has a special stack frame associated with the current task, and static
s have a "global" stack frame). (使用堆栈帧视图,就好像
@
具有与当前任务关联的特殊堆栈帧,并且static
s具有“全局”堆栈帧)。
There's also a lifetimes chapter of the book , and this gist (NB. the code is now outdated but the concepts are still true) is a neat little demonstration of how one can use lifetimes to avoid having to copy/allocate (with a strong safety guarantee: no possibility of dangling pointers). 本书还有一个生命周期章节 , 这个要点 (注意代码现已过时,但概念仍然是真的)是一个简洁的小演示,说明如何使用生命周期来避免复制/分配(具有强大的安全性)保证:没有悬挂指针的可能性)。
And while I'm at it, what is
'self
?虽然我在这,但是什么是
'self
?
Literally nothing special, just certain places require types to have lifetimes (eg in struct/enum defintions and in impl
s), and currently 'self
and 'static
are the only accepted names. 从字面上看,没什么特别的,只是某些地方需要类型才能有生命周期(例如在结构/枚举定义和
impl
),而目前'self
和'static
是唯一被接受的名称。 'static
for global always-valid pointers, 'self
for something that can have any lifetime. 'static
用于全局永远有效的指针, 'self
为可以有任何生命周期的东西。 It's a bug that calling that (non- static
) lifetime anything other than self
is an error. 这是调用一个(非错误
static
)比其他任何一辈子self
是一个错误。
All in all, I'd write that function like: 总而言之,我写的功能如下:
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
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.