Rust 如何实现反射? [英] How does Rust implement reflection?

查看:38
本文介绍了Rust 如何实现反射?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Rust 具有 Any 特性,但它也有不为不使用的东西付费"的政策.Rust 如何实现反射?

Rust has the Any trait, but it also has a "do not pay for what you do not use" policy. How does Rust implement reflection?

我的猜测是 Rust 使用了惰性标记.每个类型最初都是未分配的,但稍后如果将该类型的实例传递给需要 Any 特征的函数,则该类型会被分配一个 TypeId.

My guess is that Rust uses lazy tagging. Every type is initially unassigned, but later if an instance of the type is passed to a function expecting an Any trait, the type is assigned a TypeId.

或者,Rust 可能会在其实例可能传递给该函数的每个类型上放置一个 TypeId ?我猜前者会很贵.

Or maybe Rust puts a TypeId on every type that its instance is possibly passed to that function? I guess the former would be expensive.

推荐答案

首先,Rust 没有反射;反射意味着您可以在运行时获取有关类型的详细信息,例如它实现的字段、方法、接口等. 您不能使用 Rust 来做到这一点.您能得到的最接近的是显式实现(或派生)提供此信息的特征.

First of all, Rust doesn't have reflection; reflection implies you can get details about a type at runtime, like the fields, methods, interfaces it implements, etc. You can not do this with Rust. The closest you can get is explicitly implementing (or deriving) a trait that provides this information.

每种类型都会在编译时获得一个分配给它的 TypeId.因为拥有全局排序的 ID 很难,所以 ID 是一个整数,它是从类型定义和有关包含它的 crate 的各种元数据的组合中派生出来的.换句话说:它们没有按任何顺序分配,它们只是定义类型的各种信息的散列.[1]

Each type gets a TypeId assigned to it at compile time. Because having globally ordered IDs is hard, the ID is an integer derived from a combination of the type's definition, and assorted metadata about the crate in which it's contained. To put it another way: they're not assigned in any sort of order, they're just hashes of the various bits of information that go into defining the type. [1]

如果您查看 Any trait,你会看到 Any 的单一实现:

If you look at the source for the Any trait, you'll see the single implementation for Any:

impl<T: 'static + ?Sized > Any for T {
    fn get_type_id(&self) -> TypeId { TypeId::of::<T>() }
}

(边界可以非正式地简化为所有不是从其他东西借来的类型".)

(The bounds can be informally reduced to "all types that aren't borrowed from something else".)

你也可以找到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 位整数.

intrinsics::type_id is an internal function recognised by the compiler that, given a type, returns its internal type ID. This call just gets replaced at compile time with the literal integer type ID; there's no actual call here. [2] That's how TypeId knows what a type's ID is. TypeId, then, is just a wrapper around this u64 to hide the implementation details from users. If you find it conceptually simpler, you can just think of a type's TypeId as being a constant 64-bit integer that the compiler just knows at compile time.

Anyget_type_id 转发到 this,这意味着 get_type_id 真的 只是将 trait 方法绑定到适当的 TypeId::of 方法.它只是为了确保如果您有 Any,您可以找出原始类型的 TypeId.

Any forwards to this from get_type_id, meaning that get_type_id is really just binding the trait method to the appropriate TypeId::of method. It's just there to ensure that if you have an Any, you can find out the original type's TypeId.

现在,Any 是为大多数类型实现的,但这并不意味着所有这些类型实际上都有一个 Any 在内存中浮动的实现.实际发生的是,如果某人编写需要它的代码,编译器只会为类型的Any实现生成实际代码.[3] 换句话说,如果你从不为给定的类型使用 Any 实现,编译器将永远不会生成它.

Now, Any is implemented for most types, but this doesn't mean that all those types actually have an Any implementation floating around in memory. What actually happens is that the compiler only generates the actual code for a type's Any implementation if someone writes code that requires it. [3] In other words, if you never use the Any implementation for a given type, the compiler will never generate it.

这就是 Rust 实现不为不使用的东西付费"的方式:如果您从未将给定类型作为 &AnyBox 传递,则永远不会生成相关代码,也永远不会占用已编译二进制文件中的任何空间.

This is how Rust fulfills "do not pay for what do you not use": if you never pass a given type as &Any or Box<Any>, then the associated code is never generated and never takes up any space in your compiled binary.

[1]:令人沮丧的是,这意味着类型的 TypeId 可以改变值,具体取决于如何编译库,到将其编译为依赖项(而不是作为独立构建)会导致 TypeIds 更改.

[1]: Frustratingly, this means that a type's TypeId can change value depending on precisely how the library gets compiled, to the point that compiling it as a dependency (as opposed to as a standalone build) causes TypeIds to change.

[2]:据我所知.我可能在这件事上错了,但如果是这样的话,我真的会感到惊讶.

[2]: Insofar as I am aware. I could be wrong about this, but I'd be really surprised if that's the case.

[3]:这对于 Rust 中的泛型通常是正确的.

[3]: This is generally true of generics in Rust.

这篇关于Rust 如何实现反射?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆