Explicit lifetime bound required by TypeId::of::<T>

Hi,
The following snippet...

struct TypeNameLookUp {
    table: HashMap<TypeId, String>
}

impl TypeNameLookUp {
    pub fn get<T>(&self) -> Option<&String> {
        self.table.get(&TypeId::of::<T>())
    }
}

results in...

fn of<T>() -> TypeId
the parameter type `T` may not live long enough
...so that the type `T` will meet its required lifetime boundsrustcE0310
main.rs(256, 16): consider adding an explicit lifetime bound...

There are two things I struggle with here.

  1. What is the right solution to this problem?
  2. The error message says "type 'T'". What I'm having trouble wrapping my head around is why an explicit lifetime is required for a type. Had there been references to instances of T used in the implementation of the get() method then I think the error message would have more sense.

Help is welcome :slight_smile:

Many thanks,
Michael

You want to constrain T by making the type parameter T: 'static.

The error message seems a bit lacking, looks like there's room for improvement there.

The error message for me looks like

error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:16:25
   |
15 |     pub fn get<T>(&self) -> Option<&String> {
   |                - help: consider adding an explicit lifetime bound...: `T: 'static`
16 |         self.table.get(&TypeId::of::<T>())
   |                         ^^^^^^^^^^^^^^^ ...so that the type `T` will meet its required lifetime bounds

so it does seem to suggest the correct fix.

The T: 'static bound means more-or-less that the type doesn’t contain any non-'static lifetime parameters. E.g. something like T == String or T == u64 or T == Vec<&'static str> is okay but T == &'a u8 doesn’t work (unless 'a == 'static). The reason behind this is that lifetime parameters are removed during compilation and there’s no way to distinguish types such as &'a u8 and &'b u8 from each other at run-time. On the other hand TypeId is supposed to uniquely identify its type, and this is relied on by the Any trait using it internally and providing methods such as downcast_ref.

Also, I guess it’s obligatory to link this post here: rust-blog/common-rust-lifetime-misconceptions.md at master · pretzelhammer/rust-blog · GitHub

For a more complete picture, you should know of another typical application of a T: 'static bound: The thread::spawn function. This time it is needed because the closure value of type F is allowed to exit the current stack frame (by being transferred to a new thread) so it may not contain any lifetimes that bound it to that stackframe.

3 Likes