iface与eface #
接口类型“动静兼备”的特性也决定了它的变量的内部表示绝不像一个静态类型变量(如 int、float64)那样简单,我们可以在 $GOROOT/src/runtime/runtime2.go中找到接口类型变量在运行时的表示:
// $GOROOT/src/runtime/runtime2.go
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}
这两种表示分别用于不同的接口类型变量:
- eface结构 用于表示没有方法的空接口(empty interface)类型变量,也就是 interface{}类型的变量;
- iface结构 用于表示其余拥有方法的接口 interface 类型变量。
这两个结构的共同点是它们都有两个指针字段,并且第二个指针字段的功能相同,都是指向当前赋值给该接口类型变量的动态类型变量的值。
它们的不同点在于 eface 表示的空接口类型并没有方法列表,因此它的第一个指针字段指向一个_type类型结构。
而 iface 除了要存储动态类型信息之外,还要存储接口本身的信息(接口的类型信息、方法列表信息等)以及动态类型所实现的方法的信息,因此 iface 的第一个字段指向一个itab类型结构。
每个接口类型变量在运行时的表示都是由两部分组成的,针对不同接口类型我们可以简化记作:eface(_type, data)和iface(tab, data)。