Rust具有这种Any
特性,但它也有"不支付你不使用的"政策.Rust如何实现反射?
我的猜测是Rust使用了懒惰标记.每个类型最初都是未分配的,但是稍后如果将类型的实例传递给期望Any
特征的函数,则为该类型分配一个TypeId
.
或者Rust TypeId
可能会在其实例可能传递给该函数的每种类型上放置一个?我想前者会很贵.
DK.*_*DK. 58
首先,鲁斯特没有反思; 反射意味着您可以在运行时获取有关类型的详细信息,例如字段,方法,它实现的接口等. 您不能使用Rust执行此操作.您可以获得的最接近的是显式实现(或派生)提供此信息的特征.
每种类型都TypeId
在编译时分配给它.因为具有全局排序的ID 很难,所以ID是从类型的定义和关于包含它的包的各种元数据的组合得到的整数.换句话说:它们不是以任何顺序分配的,它们只是定义类型的各种信息的哈希.[1]
impl<T: 'static + ?Sized > Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
Run Code Online (Sandbox Code Playgroud)
(边界可以非正式地缩减为"所有不借用其他东西的类型".)
您还可以找到以下定义TypeId
:
pub struct TypeId {
t: u64,
}
impl TypeId {
pub const fn of<T: ?Sized + 'static>() -> TypeId {
TypeId {
t: unsafe { intrinsics::type_id::<T>() },
}
}
}
Run Code Online (Sandbox Code Playgroud)
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
对给定类型使用实现,则编译器将永远不会生成它.
这就是Rust履行"不为你不使用的东西买单"的方式:如果你从未将给定的类型作为&Any
或传递Box<Any>
,那么相关的代码永远不会生成,也不会占用已编译的二进制文件中的任何空间.
[1]:无奈的是,这意味着一个类型的TypeId
可以改变数值取决于正是如何库被编译,该编译它作为一个依赖(而不是作为一个独立的版本)的点引起TypeId
s到改变.
[2]:就我所知.我可能错了,但如果是这样的话,我会感到非常惊讶.
[3]:这对于Rust中的泛型通常是正确的.