在 【Go】内存中的谈空空接口 一文中,我们知道 interface{ } 类型的接口对象的结构如下:
// emptyInterface is the header for an interface{ } value. type emptyInterface struct { typ *rtype word unsafe.Pointer }该结构体包含两个指针,占 16 个字节。谈空
该结构体包含类型信息和数据信息,接口Go编译器可以把任何类型的谈空数据封装成该结构的对象;结果是在语法层面, interface{ } 类型的接口变量可以引用任何类型的数据, interface{ } 类型的谈空形式参数可以接收任何类型的实际参数。
前文只是接口介绍了 interface{ } 的对象结构,但还没有介绍 interface{ } 的谈空类型信息。本文将详细分析空接口的接口类型信息。
继续阅读文本之前,谈空强烈推荐优先阅读以下两篇图文:
【Go】内存中的接口空接口 【Go】深入理解函数操作系统、处理器架构、谈空Go版本不同,接口均有可能造成相同的谈空源码编译后运行时的寄存器值、内存地址、数据结构等存在差异。源码库
本文仅包含 64 位系统架构下的 64 位可执行程序的研究分析。
本文仅保证学习过程中的分析数据在当前环境下的准确有效性。
接口类型信息的结构定义在reflect/type.go源文件中:
// interfaceType represents an interface type. type interfaceType struct { rtype pkgPath name // import path methods []imethod // sorted by hash }该结构体占 80 个字节。
将接口类型信息绘制成图表如下:
再次强调,继续之前务必阅读 【Go】内存中的函数 ,方便了解本文分析过程。
定义Typeof函数的目的是方便定位 interface{ } 的类型信息,直接在该函数入口处设置断点。
在调试过程中,首先得到的是Typeof函数的类型信息。该函数只有一个参数,参数的类型信息位于内存地址 0x4a5200 处,这就是空接口的类型信息。
将空接口的类型信息做成图表如下:
从以上数据我们可以知道,interface{ } 类型的对象 16 字节大小、云服务器提供商8 字节对齐、具有可比较性,没有任何方法。
ptrToThis = 0x000067c0 是空接口指针类型(*interface{ })信息的内存偏移量。
空接口是Go语言内置的数据类型,不属于任何包,所以包路径值为空(pkgPath)。
空接口具有可比较性。
空接口类型的equal函数为runtime.nilinterequal,该函数定义在runtime/alg.go源文件中:
func nilinterequal(p, q unsafe.Pointer) bool { x := *(*eface)(p) y := *(*eface)(q) return x._type == y._type && efaceeq(x._type, x.data, y.data) } func efaceeq(t *_type, x, y unsafe.Pointer) bool { if t == nil { return true } eq := t.equal if eq == nil { panic(errorString("comparing uncomparable type " + t.string())) } if isDirectIface(t) { return x == y } return eq(x, y) } // isDirectIface reports whether t is stored directly in an interface value. func isDirectIface(t *_type) bool { return t.kind&kindDirectIface != 0 }通过源码,看到空接口对象比较的逻辑如下:
如果两个对象的类型不一样,返回 false 如果两个对象的类型一样,并且值为nil,返回 true 如果两个对象的类型一样,但是不可比较,直接 panic 然后进行比较,并返回比较结果。也就是说,空接口对象的比较,实际是其表示的香港云服务器类型和其指向的数据的比较。
通过内存中的空接口和本文,基本已经全面了解了 interface{ }。
本文转载自微信公众号「Golang In Memory」