Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lifetimes in HashMap where key refers to value [duplicate]

Tags:

rust

I'm relatively new to Rust. I want to write a function that will create a HashMap from a collection given a closure that generates a key from a value, e.g.

[derive(Debug)]
struct Foo {
    id: u32,
    name: String,
}
let foos = vec![
    Foo { id: 1, name: "Bill".to_string() },
    Foo { id: 2, name: "Mary".to_string() },
];
println!("{:?}", foos);
println!("{:?}", map_by(foos.iter(), |f|  f.id));  // borrow  the Foos
println!("{:?}", map_by(foos.iter(), |f| &f.name));          // borrow
println!("{:?}", map_by(foos.iter(), |f|  f.name.as_str())); // borrow
println!("{:?}", map_by(foos,        |f|  f.id));  // consume the Foos

I wrote this, and it works for the above uses:

fn map_by<I,K,V>(iterable: I, f: impl Fn(&V) -> K) -> HashMap<K,V>
where I: IntoIterator<Item = V>,
      K: Eq + Hash
{
    iterable.into_iter().map(|v| (f(&v), v)).collect()
}

[Foo { id: 1, name: "Bill" }, Foo { id: 2, name: "Mary" }]
{1: Foo { id: 1, name: "Bill" }, 2: Foo { id: 2, name: "Mary" }}
{"Bill": Foo { id: 1, name: "Bill" }, "Mary": Foo { id: 2, name: "Mary" }}
{"Bill": Foo { id: 1, name: "Bill" }, "Mary": Foo { id: 2, name: "Mary" }}
{2: Foo { id: 2, name: "Mary" }, 1: Foo { id: 1, name: "Bill" }}

Great! But it doesn't work when I let the HashMap OWN the values when the keys refer to them:

println!("{:?}", map_by(foos,        |f| f.name.as_str()));

error[E0495]: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements

And unfortunately the error message melted my brain. I tried specifying that the key and value have the same lifetime, but it didn't help. Here it is in a playground. What is the compiler trying to tell me, and what am I doing wrong? Surely if this can work when we borrow the values, it can work when we own them.

like image 937
AmigoNico Avatar asked Oct 18 '25 14:10

AmigoNico


1 Answers

Surely if this can work when we borrow the values, it can work when we own them.

No. A HashMap will move entries around in memory when it needs to resize itself to accommodate new entries. If the key borrows the value, and the entry is moved, then the address of the value will change and the reference in the key will no longer be valid.

For more information, see Why can't I store a value and a reference to that value in the same struct?.

like image 59
Francis Gagné Avatar answered Oct 22 '25 04:10

Francis Gagné



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!