Swift中type(of:)是如何实现对值类型的动态类型识别的?
Swift 中type(of:)获取值类型动态类型的底层逻辑
你遇到的这个疑问核心是对Any类型的底层布局不熟悉:Any不是无开销的透明容器,它自带额外的类型存储信息,你代码里只读取了它内存布局的前8字节,自然看不到后面的类型相关数据。
核心原理:存在类型的容器布局
当你把一个值类型赋值给Any、any 协议这类**存在类型(Existential Type)**变量时,Swift 会自动把值包装到「存在容器」结构里,64位系统下这个容器固定占40字节(5个8字节的机器字),结构如下:
- 前24字节(3个机器字):值缓冲区
大小不超过24字节的值类型会直接把完整内容存在这个区域,超过24字节的值类型会在堆上分配存储空间,把堆地址存在这个区域。你代码里的Foo结构体只有一个Int属性,大小只有8字节,所以直接把bar的数值10存在了这个区域的前8字节,这就是你直接取Int类型指针能拿到10的原因。 - 第4个8字节:值目击表(Value Witness Table, VWT)指针
每个 Swift 类型在编译时都会生成唯一的VWT,表内存储了该类型的内存大小、对齐规则、拷贝、销毁等生命周期操作函数,同时也存储了指向该类型元数据的指针。 - 第5个8字节:协议目击表指针
如果是带协议约束的存在类型(比如any CustomStringConvertible),这个位置存储对应协议的方法实现表指针;如果是无约束的Any类型,这个位置是空指针。
type(of:)的运行时逻辑
当你对存在类型的变量调用type(of:)时,运行时会执行以下操作:
- 定位到存在容器的第4个机器字,拿到VWT指针
- 从VWT的固定偏移位置取出预存的类型元数据指针,就能拿到该值的动态类型。
如果是没有经过存在类型抹除的普通值类型变量,type(of:)的结果在编译阶段就可以静态确定,不需要运行时查询,更不需要类似OC的isa指针。
内容的提问来源于stack exchange,提问作者Phoenix19
相关产品推荐
相关产品推荐

