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

2

9

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?

Synge answered 3/12, 2020 at 14:2 Comment(2)
Given that the example function ignores the inputs you could also write: pub fn search<'a>(_query: &str, _contents: &str) -> Vec<&'a str> But that's definitely an unusual situation.Aaren
I snipped the function logic from my question body but I see what you mean.Synge
D
9

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

Deferred answered 3/12, 2020 at 14:12 Comment(0)
A
3

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.

Aaren answered 3/12, 2020 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.