Rust HashMap insert method producing borrow-checker error with generated string

102 views Asked by At

I am trying Rust and having hard time to understand why the compiler fail my code on a lifetime issue. Here is the issue.

Here is how the code is organize using cargo workspaces.

.
├── Cargo.lock
├── Cargo.toml
├── README.md
├── collections
│   ├── Cargo.toml
│   └── src
└── utils
    ├── Cargo.toml
    └── src

I defined a function in called generate_string in utils lib which I am calling from collections.

/// defined in utils/src/lib.rs
pub fn generate_string (size: usize) -> String {
    Alphanumeric.sample_string(&mut rand::thread_rng(), size)
}

Now trying to call it from collections/src/stone.rs

mod tets { 
   fn test_normalize_large_input() {
        let map_lenght = 50000;
        let err_message = "normalize handles large inputs.";
        let mut profile: HashMap<&str, f64> = HashMap::new();
        for _ in 0..map_lenght {
            let key: String = utils::generate_string(8);
            profile.insert(&key, 1.0); // this won't work
        }
        let got = normalize(&profile).unwrap();
        assert_eq!(got.len(), 1, "{}", err_message);
        assert!(got.contains_key("singleton"), "{}", err_message);
    }
}

I have a compilation issue.

    |
462 |             let key: String = utils::generate_string(8);
    |                 --- binding `key` declared here
463 |             profile.insert(&key, 1.0);
    |                            ^^^^ borrowed value does not live long enough
464 |         }
    |         - `key` dropped here while still borrowed

This is what I don't understand. I don't see which over variable or function is borrowing the variable key. Because the insert method of HashMap does not borrow the key args when I checked the documentation.

The the questions are, 1) What is actually borrowing key ? How can I insert the return of utils::generate_string in the Map without issue ?

I tried to clone the variable key this way profile.insert(key.clone().as_str(), 1.0);. I was expecting the cloning to duplicate the memory content so that the lifetime of key is no longer an issue. But it does not work either. I get another error this time.

    |
463 |             profile.insert(key.clone().as_str(), 1.0);
    |             ---------------^^^^^^^^^^^---------------- temporary value is freed at the end of this statement
    |             |              |
    |             |              creates a temporary value which is freed while still in use
    |             borrow later used here
    |
    = note: consider using a `let` binding to create a longer lived value

In reality, I do not want to clone the variable. I did tried this to see how it will behave.

Thank you in advance for your help.

1

There are 1 answers

0
Masklinn On

I don't see which over variable or function is borrowing the variable key. Because the insert method of HashMap does not borrow the key args when I checked the documentation.

insert does not but you do when you write

profile.insert(&key, 1.0); 

That's a borrow. You're not inserting key in the map, you're inserting a reference to key.

And because key is a String which is owned by the loop's scope it is stopped at the end of that iteration, and thus the reference is dangling, which is illegal.

You need to make your map a HashMap<String, f64> so you can move key in the map, and the map owns the string from there on.

profile.insert(key.clone().as_str(), 1.0);

That's just a more complicated version of the same problem (an even worse problem in fact). key.clone() is a temporary which is dropped at the end of the statement (right after insert completes and returns), and you're inserting a reference to that temporary, which is an even shorter borrow.

You should really consider reading or re-reading the Rust book, carefully, because you're hitting your head against absolute fundamentals of the language here, and that's not going to be a fun experience. Rust is not an easy language, and unless you have master-class knowledge of C or C++ it is almost impossible to learn by just fucking around with in an editor, some of the concepts are novel, present in no non-academic languages, and as helpful as the compiler tries to be it will stop you hard and it can't provide complete guidance for the issues. Maybe one day, but not right now, and not any time soon.