理解rustc_middle中的adjustment.rs
最简单的情况是指针在 "fat"(胖)和 "thin"(瘦)之间没有进行调整。在这种情况下,指针将被解引用 N 次(解引用可以发生在原始指针或借用的指针,或者实现了
Deref
的任何智能指针,包括Box<_>
)。解引用的类型由autoderefs
给出。然后,它可以被自动引用零次或一次,由autoref
表示,引用的结果可以是原始指针或借用的指针。在这些情况下,unsize
是false
。从 "thin" 到 "fat" 的转换涉及到对底层数据的 "unsizing" 操作。我们从一个 "thin" 指针开始,解引用若干次,然后 "unsize" 底层数据,最后进行自动引用。"unsize" 阶段可能会把一个固定长度的数组转变为一个动态大小的数组,或者一个具体的对象转变为一个 trait 对象,或者一个静态大小的结构体转变为一个动态大小的结构体。例如,
&[i32; 4]
->&[i32]
的转换过程可以表示为:
Deref(None) -> [i32; 4],
Borrow(AutoBorrow::Ref) -> &[i32; 4],
Unsize -> &[i32],
- 注意,对于一个结构体,结构体的 'deep' "unsizing" 并未被记录下来。例如,对于
struct Foo<T> { x: T }
,我们可以强制将&Foo<[i32; 4]>
转换为&Foo<[i32]>
。在这种情况下,自动解引用和引用的过程与上面的例子相同,但是在unsize
中存储的类型是Foo<[i32]>
,并没有存储[i32; 4]
到[i32]
的底层转换过程。
- 将
Box<T>
强制转换为Box<dyn Trait>
是一个特别有趣的案例。在这种情况下,我们已经拥有了所需的指针,所以没有自动解引用,也没有自动引用。我们只需要做Unsize
转换。当然,在某一点上,Box
应该从编译器中移出,在这种情况下,这个过程与转换结构体类似。例如,Box<[i32; 4]>
->Box<[i32]>
就是一个Adjust::Unsize
操作,目标类型是Box<[i32]>
。
Adjustment<'tcx>
结构体具有以下字段:
kind: Adjust<'tcx>
:指示进行的调整种类。target: Ty<'tcx>
:指示调整的目标类型。
这个结构体有很多派生的 trait,如 Clone
, TyEncodable
, TyDecodable
, HashStable
, TypeFoldable
, TypeVisitable
和 Lift
,这些 trait 提供了诸如克隆、编码/解码、稳定哈希、类型折叠、类型访问和提升等功能。