Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the implicit lifetime for the 1st argument when the 2nd argument is annotated with 'a?

Tags:

rust

lifetime

While reading Chapter 12.4 of the Rust Book, I stumbled upon this function:

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    vec![]
}

I understand why the code doesn't compile without the explicit lifetime annotation for the contents argument and the return value - the lifetime elision rules do not apply for functions with at least two borrowed arguments.

But I'm curious what's the implicit lifetime annotation for the query argument. I could think of two scenarios:

// Scenario 1
pub fn search<'a>(query: &'a str, contents: &'a str) -> Vec<&'a str> {
    vec![]
}
// Scenario 2
pub fn search<'a, 'b>(query: &'b str, contents: &'a str) -> Vec<&'a str> {
    vec![]
}

Both scenarios compile, so query gets either lifetime 'a or 'b. Which one is correct?

like image 829
Paul Razvan Berg Avatar asked Dec 03 '20 14:12

Paul Razvan Berg


Video Answer


2 Answers

From the rustonomicon, under lifetime elision:

Each elided lifetime in input position becomes a distinct lifetime parameter.


You can try assigning the function to a wrong type. Compiler will tell you the correct type of the function:

let x: () = search;

Playground

Result:

error[E0308]: mismatched types
 --> src/main.rs:6:17
  |
6 |     let x: () = search;
  |            --   ^^^^^^ expected `()`, found fn item
  |            |
  |            expected due to this
  |
  = note: expected unit type `()`
               found fn item `for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}`

So, type of your function is:

for<'r, 'a> fn(&'r str, &'a str) -> Vec<&'a str> {search}

Also, if query also had lifetime 'a, you should be able to do this:

pub fn search<'a>(query: &str, contents: &'a str) -> Vec<&'a str> {
    vec![query]
}

But this fails to compile because query's lifetime is not 'a.

Playground

like image 105
Mihir Luthra Avatar answered Oct 19 '22 00:10

Mihir Luthra


One way to think of it is that we're not 'giving' a lifetime with lifetime annotations, but describing how the lifetime of your return value relates to the lifetimes of your inputs.

Lifetimes already exist, but annotations let us set relations between them. As you never relate the lifetime of query to anything else in situation 2, we shouldn't really need to name it. Intuitively this makes sense as the most common case and the one that the compiler should (does) infer if you make no annotation on query.

like image 43
matt_t_gregg Avatar answered Oct 18 '22 23:10

matt_t_gregg