Using TypeId as key in BTreeMap, lifetime question for TypeId::of::<T>

Hi there,
I do have a BTreeMap that shall use the TypeId of a type as the key. The definition is straightforward. But when using it in a generic function like:

fn bar<T: 'static>(map: &BTreeMap<TypeId, u32>, value: T) -> Result<(),()> {
    if map.contains_key(&TypeId::of::<T>()) {
        Err(())
    } else {
        Ok(())
    }
}

The TypeId::of::<T>() requires a 'static lifetime for type T. I thought, that within the generic function the type T will always live long enough to fulfill the call to TypeId::of::<T>().
I've seen that in the docs it's written:

pub const fn of<T: ?Sized + 'static>() -> TypeId

Is it "safe" though to add 'static as a lifetime bound to the parameter of my function as there is no need that the actual generic parameter has such a long lifetime as it might be dropped after the function call or just live as long as the calling function ?

Playgound

The 'static bound is not an accident. If TypeId didn't require it, it would be possible to transmute lifetimes through Any, for example. So yes, your use case does require that the type be 'static, you just didn't realize it.

4 Likes

Thanks, I was maybe confused that the 'static lifetime might require the structure passed to the function to be some kind of staticly defined....But it seems that the actually passed structure could have a shorter lifetime..

struct Foo;

fn bar<T: 'static>(value: T)> { }

fn baz() {
  let foo = Foo; // foo has a lifetime "bound" to baz, so I'd assumed this is not a 'static lifetime?
  bar(foo); // even though foo is moved to bar and dropped there it conforms to the 'static lifetime bound?
}

fn main() {
  baz();
}

Is my understanding correct here?

'static as a bound has a subtle meaning. It's a lifetime that cannot be satisfied by temporary references, so it's an indirect way of forbidding temporary references. For types that don't contain references it doesn't do anything.

2 Likes