How do I fix this struct variable lifetime issue?

It's unclear to me how to fix this even with the nice borrow checker messages.

Here's the simplified code that produces the error:

use std::collections::HashMap;

pub struct X<'a> {
    pub a: i32,
    pub b: &'a mut i32,  
}
impl<'a> X<'a> {
    pub fn new(a: i32, b: &'a mut i32) -> X<'a>{
        X { a, b}
    }
}

pub fn change_hashmap(hashmap_to_change: &mut HashMap<i32, X>) {
       let mut c = 2;
       let d = 1;
       
       let x = X::new(d, &mut c);
       
       hashmap_to_change.insert(d, x);
}

pub fn main() { 
    let mut hashmap1: HashMap<i32, X> = HashMap::new();
    change_hashmap(&mut hashmap1);
}
   Compiling playground v0.0.1 (/playground)
error[E0597]: `c` does not live long enough
  --> src/main.rs:17:26
   |
13 | pub fn change_hashmap(hashmap_to_change: &mut HashMap<i32, X>) {
   |                       ----------------- has type `&mut std::collections::HashMap<i32, X<'1>>`
...
17 |        let x = X::new(d, &mut c);
   |                          ^^^^^^ borrowed value does not live long enough
18 |        
19 |        hashmap_to_change.insert(d, x);
   |        ------------------------------ argument requires that `c` is borrowed for `'1`
20 | }
   | - `c` dropped here while still borrowed

error: aborting due to previous error

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

To learn more, run the command again with --verbose.

I'm no expert but I can try.
X has a borrow of c that dies at the end of the function, The hashmap owns X and it lives even after the function ends then your X will have a dangling pointer and because of that it does not compile.

In other word, the error is because hashmap has X who borrows data and needs it to live at least the what X lives but it doesn't because is cleaned after the function ends meanwhile X keep existing as a part of the Hashmap. If you want to solve that make c live at least or longer that X (for example here create c outside and pass it to the function)

1 Like

Sometimes writing out the lifetimes and types explicity can help clarify things. In this case:

The problem you have is that you’re trying to store a reference to a local variable (c) into a type tagged with a lifetime that lives longer than the function (X<'b>)— as soon as the function returns, there’s no value to reference.

If c needs to be generated by change_hashmap, you’ll need to store it somewhere it can live after the function returns. The simplest choice is to make X.b an i32 instead of a reference.

If you can’t change the X structure for some reason, you’ll need to get the &mut reference from somewhere that lives longer than the HashMap, like the function that owns it.

1 Like

Just to confirm, @PatatasDelPapa's analysis is correct. Your x does not have ownership of c, but x lives until after the end of the function, which c does not, hence the lifetime error.

2 Likes

Thank you! Nice explanation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.