rustmutexlazy-static

How to insert a String variable to a global mutable HashMap(using lazy_static and Mutex) without causing "does not live long enough" problem?


I am using Rust and I want to use a global mutable HashMap for convenience. However, while it is possible to define a global, mutable HashMap using lazy_static and Mutex, it is hard for my String variable defined in my function to have the same life time of the gloabl HashMap.

I've tried insert a &str directly and it worked well. Is there any way to convert a String to pure value?

lazy_static! {
    static ref USER_TOKEN_HASHMAP: Mutex<HashMap<&'static str, &'static str>> = {
        let mut m = HashMap::new();
        Mutex::new(m)
    };
}

fn func() {
    let mut _map = USER_TOKEN_HASHMAP.lock().unwrap();
    let user_email = String::from("aaa");
    let user_password = String::from("bbb");
    _map.insert(user_email.as_str(), user_password.as_str());
}

Error Info:

`user_email` does not live long enough
values in a scope are dropped in the opposite order they are defined
rustc(E0597)

Solution

  • I've tried insert a &str directly and it worked well. Is there any way to convert a String to pure value?

    The issue here is that you're taking the problem the wrong way around: &'static str will basically only work for literals, because it means "a pointer to a string which lives somewhere else but is never collected" ('static meaning "lives forever"). Pretty much the only possible options would be static data (living in the binary itself and thus living as long at the program runs) or leaking the memory (which is not usually a good idea).

    Here what you want is that your map store the strings themselves, and when a string is removed from the map it should be collected. That's String. That's what it does and that's what it is used for. Maybe Cow<'static, str> in the odd case where you have a mix of static data and dynamically allocated data, but that doesn't seem to be the case here.

    And thus the fix is:

    lazy_static! {
        static ref USER_TOKEN_HASHMAP: Mutex<HashMap<String, String>> = Mutex::new(HashMap::new());
    }
    
    fn func() {
        let mut _map = USER_TOKEN_HASHMAP.lock().unwrap();
        let user_email = String::from("aaa");
        let user_password = String::from("bbb");
        _map.insert(user_email, user_password);
    }
    

    Incidentally I'd recommend against the _ prefix of _map: it means you want the item named / alive for some reason but you don't want to use it (unused bindings prefixed with _ are not warned against). Here it's being actively used, so it should not be prefixed.