Why function return type &str need lifetime

I'm trying to figure out the E0106

Here is the example

fn main() {
    let string1 = String::from("abcd");
    let string2 = "xyz";

    let result = longest(string1.as_str(), string2);
    println!("The longest string is {}", result);
}

fn longest(x: &str, y: &str) -> &str {
    if x.len() > y.len() {
        x
    } else {
        y
    }
}

Here is the compiler message

error[E0106]: missing lifetime specifier
 --> src/main.rs:9:33
  |
9 | fn longest(x: &str, y: &str) -> &str {
  |               ----     ----     ^ expected named lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`
help: consider introducing a named lifetime parameter
  |
9 | fn longest<'a>(x: &'a str, y: &'a str) -> &'a str {
  |           ++++     ++          ++          ++

For more information about this error, try `rustc --explain E0106`.

It says but the signature does not say whether it is borrowed from x or y

  1. why it has to be x or y? why can't be the value which produced inside the function?
  2. Is that it always need lifetime if the return type is reference type?
  3. There is The lifetime elision rules. Does that mean all variable has lifetime, just with the distinction between implicit and explicit?

You cannot return a reference to a value created in the function because the value will be dropped at the end of the function and then the reference would point to an invalid memory location. So you'd have to return the actual value instead of the reference.

If you have a single input paramter that has a lifetime, like for example &str then the output reference will automatically get the input lifetime. For example

fn first_10(x: &str) -> &str {
    &x[0..10]
}

works without lifetime annotations because the compiler elides the lifetimes as

fn first_10<'a>(x: &'a str) -> &'a str {
    &x[0..10]
}

If you have more then one input parameter you will have to annotate lifetimes in order to return a reference.

Not necessarily all variables, but all variables that are a reference or contain a reference have at least one lifetime associated. So for example
&str,
&i32 or

struct MyRef<'a> {
    ref: &'a i32,
}

all have lifetimes even if it's not explicitly written out.

2 Likes

How can that work? Values “produced inside the function” would die at the end of that functions and something returned from function have to exist after functions return.

Yes, but there are lifetime elision rules: when you have only one argument of function then you obviously would return something tied to it. The only other alternative is 'static and that one is less common.

Yes.

1 Like