-1

I'm trying to get a handle to an element in a mutable HashMap reference where the keys are &str.

In the example below, I'm trying to get value dict[key] so I can mutate it. How do I do this?

I've tried:

  • dict.entry(key): lifetime mismatch
  • dict.entry(&String::from(key)): borrowed value does not live long enough

e.g. this:

use std::collections::HashMap;

fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
    let num = dict.entry(&String::from(key)).or_insert(0);
    *num += 1;
    return 42;
}

Errors out with:

error[E0716]: temporary value dropped while borrowed
 --> src/lib.rs:4:27
  |
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
  |                                           - let's call the lifetime of this reference `'1`
4 |     let num = dict.entry(&String::from(key)).or_insert(0);
  |               ------------^^^^^^^^^^^^^^^^^-             - temporary value is freed at the end of this statement
  |               |           |
  |               |           creates a temporary which is freed while still in use
  |               argument requires that borrow lasts for `'1`
Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366
Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188

1 Answers1

4

Link the lifetime of the key argument to the lifetime of the keys in the HashMap:

use std::collections::HashMap;

fn do_thing<'a>(key: &'a str, dict: &mut HashMap<&'a str, u32>) -> u32 {
    *dict.entry(key).or_insert(0) += 1;
    42
}

dict.entry(key)

The error message for this version helps understand the problem:

use std::collections::HashMap;

fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
    *dict.entry(key).or_insert(0) += 1;
    42
}
error[E0623]: lifetime mismatch
 --> src/lib.rs:4:17
  |
3 | fn do_thing(key: &str, dict: &mut HashMap<&str, u32>) -> u32 {
  |                  ----                     ----
  |                  |
  |                  these two types are declared with different lifetimes...
4 |     *dict.entry(key).or_insert(0) += 1;
  |                 ^^^ ...but data from `key` flows into `dict` here

Specifically, entry will store key in the HashMap, but the value referenced by key might become invalid before the HashMap does. If that happened, the HashMap would contain a dangling reference, pointing to invalid memory. That's exactly what Rust's borrow checker prevents.

See also:

dict.entry(&String::from(key))

This can never work here, for much the same reason.

See also:

Shepmaster
  • 388,571
  • 95
  • 1,107
  • 1,366