当前位置: 首页 > 科技观察

浅谈Go语言中的空接口

时间:2023-03-17 12:55:03 科技观察

前言在【Go】内存中的空接口一文中,我们知道interface{}类型的对象的结构如下://emptyInterfaceistheheaderforaninterface{}value.typeemptyInterfacestruct{typ*rtypewordunsafe.Pointer}结构包含两个指针,占用16个字节。该结构包含类型信息和数据信息,Go编译器可以将任何类型的数据封装到该结构的对象中;结果就是在语法层面,interface{}类型的变量可以引用任意类型的数据,interface{}类型的变量形参可以接收任意类型的实参。上一篇只介绍了interface{}的对象结构,并没有介绍interface{}的类型信息。本文将详细分析空接口的类型信息。在继续阅读正文之前,强烈建议先阅读以下两幅图文:[Go]内存中的空界面[Go]深入了解功能环境OS:Ubuntu20.04.2LTS;不同的设备架构和Go版本在编译运行相同的源代码时可能会导致寄存器值、内存地址和数据结构的差异。本文仅包括64位系统架构下64位可执行程序的研究和分析。本文仅保证当前环境下学习过程中分析数据的准确性和有效性。代码列表packagemainimport"fmt"import"reflect"funcmain(){Typeof(Typeof)}//go:noinlinefuncTypeof(iinterface{}){t:=reflect.TypeOf(i)fmt.Println("函数类型",t.String())fmt.Println("参数类型",t.In(0).String())}操作结果接口类型接口类型信息的结构定义在reflect/type.go源文件中://interfaceType代表一个interfacetype.typeinterfaceTypestruct{rtypepkgPathname//importpathmethods[]imethod//sortedbyhash}这个结构占用80个字节。结构分布图将接口类型信息绘制成图表如下:内存分析再次提醒,在继续理解本文的分析过程之前,一定要阅读【Go】FunctionsinMemory。定义Typeof函数的目的是方便定位interface{}的类型信息,直接在函数入口处设置断点。在调试过程中,首先要获取的是Typeof函数的类型信息。该函数只有一个参数,参数的类型信息位于内存地址0x4a5200处,为空接口的类型信息。将空接口的类型信息做成图表如下:rtype.size=16rtype.ptrdata=16rtype.hash=0x18a057e7rtype.tflag=2=reflect.tflagExtraStarrtype.align=8rtype.fieldAlign=8rtype。kind=20=reflect.Interfacertype.equal=0x4c2ba8=runtime.nilinterequalrtype.str=0x000030b0=>*interface{}rtype.ptrToThis=0x000067c0interfaceType.pkgPath=0=nilinterfaceType.methods.Data=0x4a5220interfaceType.methods。Len=interfaceType.methods.Cap=0从上面的数据可以知道,interface{}类型的对象,大小为16字节,8字节对齐,可比较,没有方法。ptrToThis=0x000067c0是空接口指针类型(*interface{})信息的内存偏移量。空接口是Go语言内置的数据类型,不属于任何包,所以包路径值为空(pkgPath)。可比性空接口是可比的。空接口类型的equal函数是runtime.nilinterequal,定义在runtime/alg.go源文件中:funcnilinterequal(p,qunsafe.Pointer)bool{x:=*(*eface)(p)y:=*(*eface)(q)返回x._type==y._type&&efaceeq(x._type,x.data,y.data)}funcefaceeq(t*_type,x,yunsafe.Pointer)bool{ift==nil{returntrue}eq:=t.equalifeq==nil{panic(errorString("comparinguncomparabletype"+t.string()))}ifisDirectIface(t){returnx==y}returneq(x,y)}//isDirectIfacereportswhethertisstoreddirectlyinaninterfacevalue.funcisDirectIface(t*_type)bool{returnt.kind&kindDirectIface!=0}通过源码可以看出比较空接口对象的逻辑如下:如果两个对象的类型不同,则返回false如果是两个对象相同且值为nil,返回true如果两个对象的类型相同,但不可比较,panic直接比较,返回比较结果。也就是说,一个空接口对象的比较,实际上是比较它所代表的类型和它所指向的数据。通过内存中的空接口和这篇文章,基本对interface{}有了一个全面的了解。本文转载自微信公众号「记忆中的Golang」