gpt4 book ai didi

reflection - Rust 是如何实现反射的?

转载 作者:行者123 更新时间:2023-11-29 07:40:14 29 4
gpt4 key购买 nike

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

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

或者也许 Rust 将 TypeId 放在它的实例可能传递给该函数的每个类型上?我猜前者会很贵。

最佳答案

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

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

如果您查看 source for the 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 位整数。

Anyget_type_id 转发到此,意思是 get_type_id 真的只是将特征方法绑定(bind)到适当的 TypeId::of方法。它只是为了确保如果你有 Any , 你可以找出原始类型的 TypeId .

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

这就是 Rust 实现“不为你不用的东西付费”的方式:如果你从未将给定类型作为 &Any 传递或 Box<Any> ,则永远不会生成关联的代码,也不会占用编译后的二进制文件中的任何空间。


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

[2]:据我所知。我可能在这方面是错的,但如果是这样的话,我真的会感到惊讶。

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

关于reflection - Rust 是如何实现反射的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36416773/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com