非空接口通过iface结构中的tab指针(指向itab,含类型信息和方法地址)和data指针(指向具体数据)实现多态;空接口eface仅含_type指针和data指针,无方法调用。

golang 接口的底层实现依赖于几个关键的数据结构,其核心在于存储类型信息和实际数据的指针。理解这些指针是掌握接口动态调用机制的关键。
非空接口:iface 结构与两个核心指针
一个包含方法定义的接口(非空接口)在运行时由 iface 结构表示。这个结构体包含两个至关重要的指针:
- tab 指针 (*itab):指向一个 itab (Interface table) 结构。这个指针是接口实现多态的基础。itab 中存储了:
- 接口自身的类型信息 (
inter *interfacetype)。 - 赋给该接口的具体数据的类型信息 (
_type *_type),也就是动态类型。 - 一个函数指针数组 (
fun [1]uintptr),它包含了该具体类型所有实现了的接口方法的实际地址。当通过接口调用方法时,程序会通过这个指针数组找到并跳转到正确的函数实现。
- 接口自身的类型信息 (
- data 指针 (unsafe.pointer):指向接口所持有的具体数据的副本。这个指针的值取决于赋值给接口的是值还是指针。
无论哪种情况,Go 的值传递原则都得到了遵循。
空接口:eface 结构的精简指针
空接口 interface{} 可以接收任何类型的值,它的底层结构是 eface。相比 iface,eface 更为简单,但也包含两个指针:
- _type 指针 (*_type):直接指向被赋值给空接口的具体数据的类型元信息。这使得空接口能够知道它里面装的是什么类型的值。
- data 指针 (unsafe.Pointer):其作用与 iface 中的 data 指针完全相同,即指向具体数据的副本或指针所引用的对象。
由于空接口没有定义任何方法,因此不需要 itab 来管理方法集,也就没有 tab 指针。
立即学习“go语言免费学习笔记(深入)”;
ITAB:编译器生成的静态表
itab 结构并非在运行时动态创建,而是在编译和链接阶段由编译器和链接器预先生成,并存放在可执行文件的只读数据段(.rodata)中。它的主要特点包括:
- 静态分配:itab 在程序启动时就已确定,其内存不受垃圾回收(GC)管理。
- 唯一性:对于任意一个具体的类型实现某个特定接口的情况,全局有且仅有一个对应的 itab 实例。例如,*os.File 类型实现 io.Reader 接口,就只有一个 itab 与之对应。
- 性能权衡:通过 itab 的 fun 数组进行方法调用是一种间接调用,相比直接调用会有轻微的性能开销,但这是实现 Go 接口灵活性和多态性所必需的代价。
基本上就这些。