Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I need to specify explicit lifetimes in Rust?

If I have the two functions

// implicit
fn foo(x: &i32) {
}

// explicit
fn bar<'a>(x: &'a i32) {
}

When would foo return an error and bar be the correct function header? I'm confused as to why I would explicitly declare a lifetime:

The 'a reads ‘the lifetime a’. Technically, every reference has some lifetime associated with it, but the compiler lets you elide them in common cases.

I understand what a lifetime is, but what does explicitly specifying a lifetime 'a do for me? For reference I'm using the Rust book as reading material

like image 892
Syntactic Fructose Avatar asked Jun 26 '15 23:06

Syntactic Fructose


People also ask

Why are lifetimes necessary in Rust?

Lifetimes are what the Rust compiler uses to keep track of how long references are valid for. Checking references is one of the borrow checker's main responsibilities. Lifetimes help the borrow checker ensure that you never have invalid references.

How do lifetimes work in Rust?

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.

What are lifetime parameters Rust?

Rust uses lifetime parameters to avoid such potential run-time errors. Since the compiler doesn't know in advance whether the if or the else block will execute, the code above won't compile and an error message will be printed that says, “a lifetime parameter is expected in compare 's signature.”

What does static lifetime mean in Rust?

As a reference lifetime 'static indicates that the data pointed to by the reference lives for the entire lifetime of the running program. It can still be coerced to a shorter lifetime.


1 Answers

Practically speaking, the #1 reason you'll have to write lifetime annotations is because the compiler asks you so. It will reject function signatures which are not covered by lifetime elision rules.

I assume you would like an simple example where lifetimes are mandatory. Imagine the following scenario:

struct Blah<'a> {
    hoy: &'a u8
}

fn want_a_hoy(blah: &Blah) -> &u8 {
    blah.hoy
}

The intention is obvious, but the compiler doesn't handle it:

<anon>:7:35: 7:38 error: missing lifetime specifier [E0106]
<anon>:7     fn want_a_hoy(blah: &Blah) -> &u8 {
                                           ^~~
<anon>:7:35: 7:38 help: see the detailed explanation for E0106
<anon>:7:35: 7:38 help: this function's return type contains a borrowed value, but 
                        the signature does not say which one of `blah`'s 2 elided 
                        lifetimes it is borrowed from

In this case, annotations solve the problem:

fn want_a_hoy<'a, 'b>(blah: &'b Blah<'a>) -> &'a u8 {
    blah.hoy
}

Here you're specifying 'a twice (on Blah<'a> and &'a). This is the same lifetime! So what you're saying to the compiler here is: "This function takes a reference to a blah containing an inner reference. I will return something which lives exactly as long as the inner reference of the blah." In this case, the signature gives a strong hint that you're likely to return something coming from the innards of the blah.

like image 89
mdup Avatar answered Sep 22 '22 09:09

mdup