当前位置: 首页 > 滚动 > >正文

全球焦点!Rust 胖瘦指针 - 从 Box<[i32; N]> 到 Box<[i32]> 发生了什么

来源:哔哩哔哩    时间:2023-01-23 16:55:57

万一有人看呢?

首先,明确堆上储存了什么

毫无疑问,堆上的数据无疑就是一个长度为 N的 i32数组

然后,Box<[i32; N]>是怎么储存的

依次将结构体展开,并将指针 *const T用编译器实际行为 core::ptr::metadata::PtrComponents<T>替代


(资料图)

非零大小而具有实际内容的数据紧密排列后,最终布局为

此时,对于任意的 N

故称指向 [i32; N]的指针是瘦指针,[i32; N]实现了特性 Thin = Pointee<Metadata = ()>

那么,Box<[i32]>是怎么储存的

同样进行展开,但是指针的元数据类型发生了改变

紧密排列后的最终布局为

此时

故称指向 [i32]的指针是胖指针,[i32]实现了特性 Pointee<Metadata = usize>

转换过程中发生了什么

很显然,在 *const [i32; N] as *const [i32]的过程中,从编译时具有的类型信息中抹去了 N,就必须在运行时具有的内存数据中放下 N

那么,从 Box<i32>到 Box<dyn Any>

堆上的数据非常简单

而 Box<i32>则为

排列毫无疑问

那么 Box<dyn Any>

排列则增加了虚表

此时

因此指向 dyn Any的指针也是胖指针,dyn Any实现了特性 Pointee<Metadata = DynMetadata<dyn Any>>

那么,虚表是什么

虚表对于用户来说是外部的类型,虽然我们不知道外部类型的大小,extern_type没有实现 Sized,但指向外部类型的指针依然是瘦的,extern_type实现了 Thin

最后一个问题,虚表有什么

很显然,在 *const i32 as *const dyn Any的过程中,从编译时具有的类型信息中抹去了实际数据类型布局和虚方法表,就必须在运行时具有的内存数据中放下它们

数据类型的布局,包括对齐和大小

虚方法表则包括特性及其父特性要求的所有方法,以及可能具有的最为特殊的 Drop::drop方法实现

一些其他内容

Thin和 Sized的关系是什么

Thin是 Sized和 extern_type的总和,实践中具有 Sized: ThinSized比 Thin更严格

如何获取 DynMetadata<Dyn>的布局

DynMetadata<Dyn>::layout(self) -> Layout获取布局,布局由对齐和大小两个部分组成

DynMetadata<Dyn>::size_of(self) -> usize获取大小

DynMetadata<Dyn>::align_of(self) -> usize获取对齐

如何在泛型中表示像 [i32; N]与 [i32]i32与 dyn Any之间的关系

使用 T: Unsize<Dyn>其中 core::marker::Usize<T: ?Sized>

具有此关系后,可以在他们的指针上使用 as

如何在泛型中表示像 Box<[i32; N]>与 Box<[i32]>Box<i32>与 Box<dyn Any>之间的关系

使用 BoxT: CoerceUnsized<BoxDyn>其中 core::ops::unsize::CoerceUnsized<T: ?Sized>

具有此关系后,可以在他们上使用 as

其他的其他

本文提及的一些特性还未稳定,如果你在代码中使用,需要 nightly 版本编译器并声明需要的功能

#![feature(unsize)]允许 trait Unsize的使用

#![feature(coerce_unsized)]允许 trait CoerceUnsized的使用

#![feature(ptr_metadata)]允许指针元数据相关API的使用

#![feature(extern_types)]允许外部类型的使用

本文在未使用分配器的情况下讨论,如果使用分配器API,情况可能发生改变

X 关闭

推荐内容

最近更新

Copyright ©  2015-2022 大众洁具网  版权所有    
备案号:豫ICP备20014643号-14     
 联系邮箱: 905 14 41 07@qq.com