What's the reason of this Compile Error?

fn exp3() {
    let mut map = HashMap::new();
    let s1: String = "hello".to_string();
    map.insert(&s1, 1);
    // dbg!(s1);
    dbg!(map.entry(&"hello".to_string()));
    let count = map.entry(&s1).or_insert(0);
    dbg!(&count);
    *count += 1;
}

The compiler complains:

error[E0716]: temporary value dropped while borrowed
  --> _6_15/src/main.rs:28:21
   |
28 |     dbg!(map.entry(&"hello".to_string()));
   |     ----------------^^^^^^^^^^^^^^^^^^^--
   |     |               |
   |     |               creates a temporary which is freed while still in use
   |     temporary value is freed at the end of this statement
29 |     let count = map.entry(&s1).or_insert(0);
   |                 -------------- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

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

I don't fully understand what happened here. Could someone explain it? Thx :wink:

You create a String, but don't store it in a variable anywhere -- that's the temporary:

                    "hello".to_string()

Then you take a reference to it and call entry on your map with it:

     map.entry(&    "hello".to_string()    )
//             ^ Let's call this lifetime 'temp

The temporary is going to drop at the end of the statement. We'll come back to the lifetime shortly.

What's the type of your map, anyway? The compiler has to infer it, since you didn't specify. How does it do so? From how you use it. Let's look at the signature of insert and entry for example:

pub fn insert(&mut self, k: K, v: V) -> Option<V>
pub fn entry(&mut self, key: K) -> Entry<'_, K, V>

They take owned keys, because you are potentially adding a new key to the HashMap. That means your map must have type HashMap<&'map String, _>, for some lifetime 'map -- because you're passing &Strings into insert and entry. This lifetime has in include the uses, including uses of anything you borrow from the map. That's basically the whole function from the insert to the end.

Now, how about the lifetime 'temp? You're adding it to map [1], so it must be at least as long as 'map -- the entire function. That means you're trying to create a borrow that lasts longer than your temporary, hence the error.

Your borrow is "used" the next time you use the map, in the compilers language, because the lifetime of 'temp and 'map became intertwined once you called entry. As far as the compiler can understand, you might have put a reference to the temporary in the map, and then tried to read it again on the next line after the temporary dropped.


  1. as far as the compiler can tell -- more accurately, you're calling a method that requires it to be coercible to the key type, so at least as long as 'map ↩ī¸Ž

2 Likes

I get what you mean. It seems difficult to deal with lifetime correctly for me. Is there any tool or plugin on VsCode which could note the lifetime explicitly?

Not that I know of. I think such a tool would be great, though. It's a bit tricky however - lifetimes used to be a lexical scope, but now they're a set of points which could have gaps -- and flow sensitive, so the lifetime from the if branch might be different than that from the else branch for example. Still, even a best effort would be appreciated.

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.