您现在的位置是:亿华云 > 数据库
Go语言之再谈空接口
亿华云2025-10-09 01:34:37【数据库】9人已围观
简介前言在 【Go】内存中的空接口 一文中,我们知道 interface{} 类型的对象的结构如下://emptyInterfaceistheheaderforaninterface{}value.typ
前言
在 【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】深入理解函数环境
OS : Ubuntu 20.04.2 LTS; x86_64 Go : go version go1.16.2 linux/amd64声明
操作系统、处理器架构、谈空Go版本不同,接口均有可能造成相同的谈空源码编译后运行时的寄存器值、内存地址、数据结构等存在差异。亿华云计算
本文仅包含 64 位系统架构下的 64 位可执行程序的研究分析。
本文仅保证学习过程中的分析数据在当前环境下的准确有效性。
代码清单
package main import "fmt" import "reflect" func main() { Typeof(Typeof) } //go:noinline func Typeof(i interface{ }) { t := reflect.TypeOf(i) fmt.Println("函数类型", t.String()) fmt.Println("参数类型", t.In(0).String()) }运行结果
接口类型
接口类型信息的结构定义在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」
很赞哦!(2)