所以,在:
fn v1<'a> (a:~[&'a str]) -> ~[&'a str] {
return a;
}
#[test]
fn test_can_create_struct() {
let x = v1("Hello World".split(' ').collect());
}
我知道,我已阅读http://static.rust-lang.org/doc/master/guide-lifetimes.html#named-lifetimes,但我不明白此代码实际上做了什么。
该函数基本上是参数化的,就像通用的fn但有生命周期,是我在IRC频道上看过的,但让我们想象就是这样,我们有一个L,这是一些特定的生命周期结构。
显然我暗中打电话:
v1::<L>("Hello World".split(' ').collect());
..但我不是。传递给此函数的生命周期是生命周期的实例,它不是生命周期的类型,因此注释对我没有任何意义。
我的意思是,我基本上了解最新情况(我认为):返回的~[&str]
与调用者的范围具有相同的生命周期,可能是test_can_create_struct()
函数。那是因为(据我所知),函数v1
是使用来自调用函数的生命周期实例调用的。
非常混乱。
然后我们还有其他一些例子: https://gist.github.com/bvssvni/8970459
这是一个片段:
impl<'a> Data<'a> {
pub fn new() -> Data<'a> {
Data { a: None, b: None }
}
pub fn a(&'a mut self, a: int) -> State<'a, Step1> {
self.a = Some(a);
State { data: self }
}
}
现在我天真地假设Data<'a>
意味着函数a()
的生命周期实例是相同的。
即。如果您创建Data
(let blah = Data::new()
)并致电blah.a()
,则生命周期将从创建调用继承;即,只要父State
对象发生,返回的Data
对象将存在。
......但显然这也是错的。所以我现在根本不知道生命周期变量的含义。
帮助!
答案 0 :(得分:19)
所以回答这个问题最简单的方法就是退后一步,引导你了解一生的实际情况。
让我们采取一个简单的功能:
fn simple_function() {
let a = MyFoo::new();
println("{}", a);
}
在这个函数中,我们有一个变量a
。与所有变量一样,此变量可以存在一段时间。在这种情况下,它一直存在于函数的末尾。当函数结束时,a
死亡。然后,a
的生命周期可以描述为从函数的开头开始,结束于函数的结尾。
下一个函数将无法编译:
fn broken_function() -> &MyFoo {
let a = MyFoo::new();
return &a;
}
执行&a
后,您借用 参考到a
。然而,关于借贷的事情是,你应该把你借来的东西给回来。 Rust对此非常严格,并且不会让您拥有无法返回的引用。如果您借用的参考资料不再存在,那么您无法返回参考资料,而且还没有参考。
对我们的broken_function
意味着什么,因为a
在函数结束时死亡,引用无法转义函数,因为这会使它超过a
下一步是:
fn call_fn() {
let a = MyFoo:new();
{
let a_ref = &a;
let b = lifetimed(a_ref);
println!("{}", *b);
}
}
fn lifetimed<'a>(foo: &'a MyFoo) -> &'a MyBar {
return foo.as_bar();
}
以下是两个函数,call_fn
和lifetimed
,这里有一些微妙的内容,所以我会把它分解。
在call_fn
我首先创建MyFoo
的新实例并将其分配给a
,然后,我借用a
的引用并将其分配给{{1} }}。借用的东西是,当你进行借用时,生命周期信息会从你借来的变量转移到引用本身。所以现在a_ref
作为变量有自己的生命周期,它在内部范围的开头和结尾开始和结束,但a_ref
的类型也有一生,一个从a_ref
调来的。
具体的生命周期无法命名,但我们假装无论如何都可以使用数字来完成。如果a
的有效期为a
,则#1
的类型为a_ref
。当我们将&'#1 MyFoo
传递给a_ref
时,编译器会像其他类型参数一样填充生命周期参数lifetimed
。 'a
的返回类型是具有相同生命周期的引用,因此编译器会在那里填充空格。有效地拨打lifetimed
。
这就是为什么生命周期出现在类型参数列表中,它们是类型系统的一部分,如果类型不匹配,那就是错误。编译器计算出函数编译所需的生命周期,因此您不必担心它,但不会在当前函数之外查看以获取更多信息。您需要使用这些参数告诉编译器您正在调用的函数,以便它知道一切正常。
NB :您可以明确指定一个生命周期。 lifetimed(foo: &'#1 MyFoo) -> &'#1 MyBar
这是整个程序的整个生命周期。