Borrow checker and HashMap with references

Hello,

it's the first time I post here, so sorry for any mistakes.

I don't know why this is not possible. The HashMap should return a reference to data inside it. Why does it need the content of variable k2?
Furthermore it is possible to drop k2 and the code is still accepted. However, if I drop k2_data than it is a problem.
Can anyone explain the lifetimes in this scenario and what exactly is the problem here?

use std::collections::HashMap;

#[derive(Hash, PartialEq, Eq, Debug)]
struct Key<'k> {
    id: &'k Data
}

#[derive(Debug)]
struct Value<'v> {
    id: &'v Data
}

#[derive(Hash, PartialEq, Eq, Debug)]
struct Data {
    val: i32
}

struct Test<'k, 'v> {
    pub data: HashMap<Key<'k>, Value<'v>>
}

fn main() {

    // +++ create HashMap and insert data +++
    let mut test = Test { data: HashMap::new() };
    
    let k1_data = Data { val: 1 };
    let k1 = Key { id: &k1_data };

    let v1_data = Data { val: 10 };
    let v1 = Value { id: &v1_data };
    
    test.data.insert(k1, v1);

    // +++ access data +++

    // create key
    let k2_data = Data { val: 1 };
    let k2 = Key { id: &k2_data };

    // get value
    let v2 = test.data.get(&k2);
    println!("{:?}: {:?}", k2, v2.unwrap());
    //drop(k2); // no problem
    drop(k2_data); // Here is the problem. Why?
    println!("{:?}", v2.unwrap());
}

(Playground)

Thanks for any help.

Ah, yeah, this is rather unfortunate. Let 'k be the lifetime on the keys in the hashmap. Then the key-type is Key<'k>. However what happens when you go test.data.get(&k2)? Well you have to supply a key of the right type, so it should be a Key<'k>, not Key<'some_other_lifetime>. But this forces the lifetime of &k2 to also be 'k, hence it needs to live as long as the hash map.

tl;dr The signature of HashMap::get allows the hash map to store the provided reference, so the compiler ensures that your code is not invalid if it does.

Maybe I got something wrong.
You said lifetime of &k2 is 'k. However, it is possible to drop k2. It is not possible to drop k2_data.
Furthermore you said k2 must live as long as the hash map. That is not true. I can drop k2 and k2_data and use the hash map after that.

My problem is, that I cannot use v2 after k2_data was dropped and I don't know the reason for this.

Right, I mixed it up a bit. The 'k does appear in &k2 because its type is going to be &'a Key<'k> for some short 'a, and the 'a being short is why you can drop k2 but not k2_data.

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.