Lifetime strange error

I dont fully understand this error:

#[allow(unused)]
fn main() {
let v;
let g=String::from("g"); 
{
let st=String::from("abc");    
let e=A{
    field:&st
};

 v=e.get(&g);
}
v;
}
#[allow(unused)]
struct A<'a>{
    field:&'a str
}

impl<'a> A<'a> {
    fn get(&self,val:&'a str)->&'a str{
val
    }
}

(Playground)

Errors:

   Compiling playground v0.0.1 (/playground)
error[E0597]: `st` does not live long enough
  --> src/main.rs:8:11
   |
8  |     field:&st
   |           ^^^ borrowed value does not live long enough
...
12 | }
   | - `st` dropped here while still borrowed
13 | v;
   | - borrow later used here

For more information about this error, try `rustc --explain E0597`.
error: could not compile `playground` due to previous error

if we replace it :

impl<'a> A<'a> {
    fn get(&self,val:&'a str)->&'a str{
val
    }
}

with it :

impl<'a> A<'a> {
    fn get<'b>(&self,val:&'b str)->&'b str{
val
    }
}

it will work

Please run your code through rustfmt before asking a question. It's almost impossible to read it without proper formatting, and you shouldn't make it harder to help you. Here's how it would look if you do that:

#[allow(unused)]
fn main() {
    let v;
    let g = String::from("g");
    {
        let st = String::from("abc");
        let e = A { field: &st };

        v = e.get(&g);
    }
    v;
}
#[allow(unused)]
struct A<'a> {
    field: &'a str,
}

impl<'a> A<'a> {
    fn get(&self, val: &'a str) -> &'a str {
        val
    }
}
2 Likes

The compiler has this principle that if you change a function's contents without changing its signature, then this can never cause a compilation failure to happen outside that function. This is an extremely useful property to have. Writing libraries that are backwards compatible would be impossible without it. The compilation failure is a consequence of this. The issue is that there are other possible implementations of get with the same signature (the lifetimes are part of the signature) where your main function would cause problems. Imagine the following code:

#[allow(unused)]
fn main() {
    let v;
    let g = String::from("g");
    {
        let st = String::from("abc");
        let e = A { field: &st };

        v = e.get(&g);
    }
    v;
}
#[allow(unused)]
struct A<'a> {
    field: &'a str,
}

impl<'a> A<'a> {
    fn get(&self, val: &'a str) -> &'a str {
        self.field
    }
}

Here, it should be clear why it fails. The v variable becomes a reference to st, and then you use it after st has gone out of scope.

Since both programs have the same signature for the get function, then the main function must either compile with both of them, or fail to compile with both of them. Since successfully compiling is incorrect for my version, both must fail to compile.

In the version where you use a 'b lifetime instead, the program will succeed in compiling when you return val. This is not a problem because trying to return self.field causes a compilation failure inside the get function.

3 Likes

thanks