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.
insertdoes not but you do when you writeThat's a borrow. You're not inserting
keyin the map, you're inserting a reference tokey.And because
keyis aStringwhich 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 movekeyin the map, and the map owns the string from there on.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 afterinsertcompletes 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.