So, in:
fn v1<\'a> (a:~[&\'a str]) -> ~[&\'a str] {
return a;
}
#[test]
fn test_can_create_struct()
So the easiest way to answer this will be to take a step back and walk you through what a lifetime actually is.
Lets take a simple function:
fn simple_function() {
let a = MyFoo::new();
println("{}", a);
}
In this function, we have a variable, a
. This variable, like all variables, lives for a certain amount of time. In this case, it lives to the end of the function. When the function ends, a
dies. The lifetime of a
, can then be described as starting at the beginning of the function, end ending at the end of the function.
This next function won't compile:
fn broken_function() -> &MyFoo {
let a = MyFoo::new();
return &a;
}
When you do &a
, you are borrowing a reference to a
. The thing about borrowing, though, is that you are expected to give the thing you borrowed back. Rust is very strict about this, and won't let you have references you can't return. If the thing you borrowed your reference from isn't around any more, you can't return the reference and that's just not on.
What it means for our broken_function
is that, because a
dies at the end of the function, the reference can't escape the function, because that would make it outlast a
.
The next step is this:
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();
}
Here are two functions, call_fn
and lifetimed
, there's some subtle stuff going on here, so I'll break it down.
In call_fn
I first create a new instance of MyFoo
and assign it to a
, then, I borrow a reference to a
and assign it to a_ref
. The thing with borrowing is that when you do a borrow, the lifetime information is transfered from the variable you are borrowing, into the reference itself. So now a_ref
, as a variable, has its own lifetime, which starts and ends at the beginning and end of that inner scope, but the type of a_ref
also has a lifetime, the one transferred over from a
.
Concrete lifetimes can't be named, but lets pretend we can do it anyway by using numbers. If the lifetime of a
is #1
, then the type of a_ref
is &'#1 MyFoo
. When we pass a_ref
to lifetimed
, the compiler fills in the lifetime parameter 'a
like it does for other type parameters. lifetimed
's return type is a reference with the same lifetime, so the compiler fills in the space there. Effectively making a unique call to lifetimed(foo: &'#1 MyFoo) -> &'#1 MyBar
.
This is why lifetimes appear in the type parameter list, they are part of the type system, and if the types don't match up, that's an error. The compiler works out the lifetimes needed in order for the function to compile, so you never have to worry about it, but won't look outside the current function to get more information. You need to use the parameters to tell the compiler about the function you're calling so it knows that everything is ok.
NB: There is one lifetime you can explicitly name. 'static
which is the lifetime of things that last for the entire length of the program.