pub struct TypeId {/* private fields */ }Expand description
ATypeId represents a globally unique identifier for a type.
EachTypeId is an opaque object which does not allow inspection of what’sinside but does allow basic operations such as cloning, comparison,printing, and showing.
ATypeId is currently only available for types which ascribe to'static,but this limitation may be removed in the future.
WhileTypeId implementsHash,PartialOrd, andOrd, it is worthnoting that the hashes and ordering will vary between Rust releases. Bewareof relying on them inside of your code!
§Layout
Like otherRust-representation types,TypeId’s size and layout are unstable.In particular, this means that you cannot rely on the size and layout ofTypeId remaining thesame between Rust releases; they are subject to change without prior notice between Rustreleases.
§Danger of Improper Variance
You might think that subtyping is impossible between two static types,but this is false; there exists a static type with a static subtype.To wit,fn(&str), which is short forfor<'any> fn(&'any str), andfn(&'static str), are two distinct, static types, and yet,fn(&str) is a subtype offn(&'static str), since any value of typefn(&str) can be used where a value of typefn(&'static str) is needed.
This means that abstractions aroundTypeId, despite its'static bound on arguments, still need to worry about unnecessaryand improper variance: it is advisable to strive for invariancefirst. The usability impact will be negligible, while the reductionin the risk of unsoundness will be most welcome.
§Examples
SupposeSubType is a subtype ofSuperType, that is,a value of typeSubType can be used wherevera value of typeSuperType is expected.Suppose also thatCoVar<T> is a generic type, which is covariant overT(like many other types, includingPhantomData<T> andVec<T>).
Then, by covariance,CoVar<SubType> is a subtype ofCoVar<SuperType>,that is, a value of typeCoVar<SubType> can be used wherevera value of typeCoVar<SuperType> is expected.
Then ifCoVar<SuperType> relies onTypeId::of::<SuperType>() to uphold any invariants,those invariants may be broken because a value of typeCoVar<SuperType> can be createdwithout going through any of its methods, like so:
typeSubType =fn(&());typeSuperType =fn(&'static());typeCoVar<T> = Vec<T>;// imagine something more complicatedletsub: CoVar<SubType> = CoVar::new();// we have a `CoVar<SuperType>` instance without// *ever* having called `CoVar::<SuperType>::new()`!letfake_super: CoVar<SuperType> = sub;The following is an example program that tries to useTypeId::of toimplement a generic typeUnique<T> that guarantees unique instances for eachUnique<T>,that is, and for each typeT there can be at most one value of typeUnique<T> at any time.
modunique {usestd::any::TypeId;usestd::collections::BTreeSet;usestd::marker::PhantomData;usestd::sync::Mutex;staticID_SET: Mutex<BTreeSet<TypeId>> = Mutex::new(BTreeSet::new());// TypeId has only covariant uses, which makes Unique covariant over TypeAsId 🚨#[derive(Debug, PartialEq)]pub structUnique<TypeAsId:'static>(// private field prevents creation without `new` outside this modulePhantomData<TypeAsId>, );impl<TypeAsId:'static> Unique<TypeAsId> {pub fnnew() ->Option<Self> {letmutset = ID_SET.lock().unwrap(); (set.insert(TypeId::of::<TypeAsId>())).then(||Self(PhantomData)) } }impl<TypeAsId:'static> DropforUnique<TypeAsId> {fndrop(&mutself) {letmutset = ID_SET.lock().unwrap(); (!set.remove(&TypeId::of::<TypeAsId>())).then(||panic!("duplicity detected")); } }}useunique::Unique;// `OtherRing` is a subtype of `TheOneRing`. Both are 'static, and thus have a TypeId.typeTheOneRing =fn(&'static());typeOtherRing =fn(&());fnmain() {letthe_one_ring: Unique<TheOneRing> = Unique::new().unwrap();assert_eq!(Unique::<TheOneRing>::new(),None);letother_ring: Unique<OtherRing> = Unique::new().unwrap();// Use that `Unique<OtherRing>` is a subtype of `Unique<TheOneRing>` 🚨letfake_one_ring: Unique<TheOneRing> = other_ring;assert_eq!(fake_one_ring, the_one_ring); std::mem::forget(fake_one_ring);}