I would like to clarify here, citing Rust by Example
A lifetime is a construct the compiler (or more specifically, its borrow checker) uses to ensure all borrows are valid. Specifically, a variable's lifetime begins when it is created and ends when it is destroyed. While lifetimes and scopes are often referred to together, they are not the same.
Take, for example, the case where we borrow a variable via &. The borrow has a lifetime that is determined by where it is declared. As a result, the borrow is valid as long as it ends before the lender is destroyed. However, the scope of the borrow is determined by where the reference is used.
It seems that Rust book created a lot of confusion, but scope
and lifetime
are indeed different things, when we talk about simple bindings which own data (not borrow it) lifetime and scope match together.
If we have simple code like this. Lifetime of a
and b
will match with scope they are defined.
fn main() {
let a = 1;
let b = 2;
}
In this example, lender (a
) goes out of scope sooner than borrow.
fn main() {
let b;
{
let a = 1;
b = &a;
}
let c = *b;
}
It forces compiler to emit error.
error[E0597]: `a` does not live long enough
--> src/main.rs:5:9
|
5 | b = &a;
| ^^^^^^ borrowed value does not live long enough
6 | }
| - `a` dropped here while still borrowed
7 | let c = *b;
| -- borrow later used here
So here b
has a lifetime longer than the lifetime of a
, because it has a greater scope. Remember that scope of borrow is determined by where the reference is used.
But this code compiles just fine, because b
scope doesn't end after a
is dropped.
fn main() {
let b;
{
let a = 1;
b = &a;
let c = *b;
}
}
Another thing to clarify is that lifetime syntax for reference &'lifetime
means. It means that reference should live as long as 'lifetime
lifetime. It shouldn't be exactly that lifetime.
Suppose Record
element is defined like this.
struct Record<'a> {
some_member: &'a Type
}
This signature just means that some member of record should live as long as reference passed to input
or vice versa.
fn parse_record<'i>(input: &'i [u8]) -> Record<'i> { ... }
If I translate it to plain English. Lender of the reference passed to the function shouldn't go out of scope (dropped) as long as a field inside Record
didn't go out of scope.
Or return value of function should live as long as input argument of function.
If we don't have return value which is constrained by the input lifetime, translation changes.
fn test<'a>(a: &'a i32, b: &'a i32)
This means that lenders of a
and b
should be in scope together until function execution ends.
In many simple cases lifetimes are elided by compiler and you shouldn't worry about them. Actually in your example too, lifetimes can be elided.
fn parse_record(input: &[u8]) -> Record { ... }
I recommend you to read Rust by Example
chapters on lifetimes to more practically understand them.
result
can only live as long asv
. It can have a shorter or equal lifetime, but not greater. As soon asv
goes out of scope,result
is no longer valid. – joel