Rust有Any
trait,但它也有一个“不为不必要的东西付费”的政策。Rust是如何实现反射的?
我猜测Rust使用了延迟标记技术。每个类型最初都没有分配,但是如果该类型的实例被传递给期望Any
trait的函数时,该类型将被分配一个TypeId
。
或者Rust在其实例可能被传递给该函数的每种类型上放置一个TypeId
?我猜前者会比较昂贵。
Rust有Any
trait,但它也有一个“不为不必要的东西付费”的政策。Rust是如何实现反射的?
我猜测Rust使用了延迟标记技术。每个类型最初都没有分配,但是如果该类型的实例被传递给期望Any
trait的函数时,该类型将被分配一个TypeId
。
或者Rust在其实例可能被传递给该函数的每种类型上放置一个TypeId
?我猜前者会比较昂贵。
Any
trait的源代码, 您将看到Any
的唯一实现。impl<T: 'static + ?Sized > Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
TypeId
的定义:pub struct TypeId {
t: u64,
}
impl TypeId {
pub const fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
}
intrinsics::type_id
是编译器识别的内部函数,给定一个类型,返回其内部类型ID。该调用只是在编译时被替换为字面整数类型ID;这里没有实际调用。[2]这就是TypeId
如何知道一个类型的ID。然后,TypeId
只是一个包装器,将此u64隐藏起来,以使用户看不到实现细节。如果您觉得概念上更简单,可以将类型的TypeId
视为编译器在编译时就“知道”的常量64位整数。
Any
从get_type_id
转发到此,这意味着get_type_id
实际上只是将特性方法绑定到适当的TypeId::of
方法。它只是确保如果您有一个Any
,则可以找到原始类型的TypeId
。
Any
已经为 大多数 类型实现了,但这并不意味着所有这些类型都 实际上拥有 一个在内存中漂浮的 Any
实现。实际发生的是,编译器只有在 有人 编写需要它的代码时才会生成类型的 Any
实现的实际代码 [3]。换句话说,如果您从未使用过给定类型的 Any
实现,则编译器将永远不会生成它。&Any
或 Box<Any>
传递,那么相关的代码将永远不会生成,也不会占用编译后二进制文件中的任何空间。
TypeId
值可能会因编译库的方式不同而发生变化,以至于将其作为依赖项编译(而非独立构建)会导致 TypeId
发生改变。
TypeId
,以进行有限形式的针对每种类型的特殊处理,而无需使用Any
。 - blussdynamic_cast
一样,只是RTTI。 - Konraddynamic_cast
,因为它没有必要的RTTI。 - DK.