首先,Rust没有反射;反射意味着你可以在运行时获得关于类型的细节,比如字段,方法,它实现的接口,等等。你不能在Rust中做到这一点。你可以得到的最接近的是显式实现(或派生)一个提供这些信息的trait。 每个类型在编译时都会被分配一个TypeId。因为全局排序的ID是 * 硬 * 的,所以ID是一个整数,它来自于类型定义的组合,以及包含它的crate的各种元数据。换句话说:它们并没有以任何顺序赋值,它们只是定义类型的各种信息的 * 散列 *。 如果你看一下source for the Any trait,你会看到Any的单一实现:
impl<T: 'static + ?Sized > Any for T {
fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}
1条答案
按热度按时间g52tjvyc1#
首先,Rust没有反射;反射意味着你可以在运行时获得关于类型的细节,比如字段,方法,它实现的接口,等等。你不能在Rust中做到这一点。你可以得到的最接近的是显式实现(或派生)一个提供这些信息的trait。
每个类型在编译时都会被分配一个
TypeId
。因为全局排序的ID是 * 硬 * 的,所以ID是一个整数,它来自于类型定义的组合,以及包含它的crate的各种元数据。换句话说:它们并没有以任何顺序赋值,它们只是定义类型的各种信息的 * 散列 *。如果你看一下source for the
Any
trait,你会看到Any
的单一实现:字符串
(The边界可以 * 非正式地 * 简化为“所有不从其他东西借用的类型”。
你也可以找到
TypeId
的定义:型
intrinsics::type_id
是编译器识别的内部函数,给定类型,返回其内部类型ID。此调用仅在编译时被替换为文字整数类型ID;这里没有 actual 调用。[2]这就是TypeId
如何知道类型的ID是什么。TypeId
,那么,u64
只是一个 Package 器,用来对用户隐藏实现细节。如果你觉得它在概念上更简单,你可以把类型的TypeId
看作是一个常量64位整数,编译器在编译时只知道它。Any
从get_type_id
转发到this,这意味着get_type_id
* 实际上 * 只是将trait方法绑定到适当的TypeId::of
方法。它只是为了确保如果您有Any
,您可以找到原始类型的TypeId
。现在,
Any
是为 * 大多数 * 类型实现的,但这并不意味着所有这些类型 * 实际上都有 * 一个Any
实现在内存中浮动。实际发生的是,编译器只在 * 某人 * 编写需要它的代码时才为类型的Any
实现生成实际代码。[3]换句话说,如果你从来没有为一个给定的类型使用Any
实现,编译器将永远不会生成它。这就是Rust如何实现“不为你不使用的东西付费”:如果你从来没有把一个给定的类型作为
&Any
或Box<Any>
传递,那么相关的代码永远不会生成,也不会占用你编译的二进制文件中的任何空间。[1]令人沮丧的是,这意味着一个类型的
TypeId
可以根据库的编译方式来改变值,以至于将其编译为依赖项(而不是独立构建)会导致TypeId
s改变。[2]我知道我可能错了,但如果是这样的话,我会感到非常惊讶。
[3]:Rust中的泛型 * 通常 * 是这样的。