Reputation: 10153
I'm trying to understand how changing the value type in a HashMap from &'t str
to Value<'t>(&'t str)
leads to a stricter requirement on the Key
type passed in to get
below.
#![allow(dead_code, unused)]
use std::collections::HashMap;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct Key<'t>(&'t str);
#[derive(Debug, Clone, Copy)]
struct Value<'t>(&'t str);
#[derive(Debug)]
struct Map1<'t>(HashMap<Key<'t>, &'t str>);
#[derive(Debug)]
struct Map2<'t>(HashMap<Key<'t>, Value<'t>>);
impl<'t> Map1<'t> {
fn get<'map>(&'map self, key: &Key<'_>) -> Option<&'map str> {
self.0.get(key).map(|x| *x)
}
}
impl<'t> Map2<'t> {
fn get<'map>(&'map self, key: &Key<'_>) -> Option<&'map Value<'t>> {
// Doesn't work, says: -------- help: add explicit lifetime `'map` to the type of `key`: `&Key<'map>`
self.0.get(key)
}
}
In Map1
with value type &'t str
it's fine to pass in a Key
with any lifetime, whereas in Map2
with value type Value<'t>
(a new type wrapper around &'t str
) it is no longer fine and I'm expected to pass a key whose inner lifetime is as long as the map itself.
Could you help me understand why this the case?
Is there anything I can do to make the new type wrapped Value(&str)
work the same as a &str
?
Upvotes: 2
Views: 58
Reputation: 4231
The two get
implementations are not equivalent:
self.0.get(key).map(|x| *x)
// vs
self.0.get(key)
what the map
is doing is essentially a copy()
. What would be the type of the Map1::map
method without that copy?
impl<'t> Map1<'t> {
fn get<'map>(&'map self, key: &Key<'_>) -> Option<&'map &'t str> {
self.0.get(key)
}
}
... which gives you the same error.
So, what you really need is to copy that Value
, e.g. like this:
impl<'t> Map2<'t> {
fn get<'map>(&'map self, key: &Key<'_>) -> Option<Value<'t>> {
self.0.get(key).copied()
}
}
If you want to not do that, then naturally you will need to change the lifetime declaration compared to Map1
.
Upvotes: 2