数据类型
接口的定义
interfaceimplements
有时候我们称这种模型叫做鸭子模型(Duck typing),维基百科对鸭子模型的定义是
”If it looks like a duck, swims like a duck, and quacks like a duck, then it probably is a duck.“
翻译过来就是 ”如果它看起来像鸭子,像鸭子一样游泳,像鸭子一样嘎嘎叫,那他就可以认为是鸭子“。
Go 不同版本之间interface的结构可能不太一样,但整体都差不多,这里使用的Go版本为 1.15.6。
数据结构interfaceefaceiface
efacevar x interface{}func Println(a ...interface{}) (n int, err error) {}eface
iface
ifaceefaceeface
对数据结构的定义若不指定的话,默认位于 。
doSomething(v interface{})vinterface
eface 结构体
我们看一下空接口的结构体定义
// src/runtime/runtime2.go type eface struct { _type *_type data unsafe.Pointer }
eface_typedata
runtime._type 结构定义如下
// src/runtime/type.go // Needs to be in sync with ../cmd/link/internal/ld/decodesym.go:/^func.commonsize, // ../cmd/compile/internal/gc/reflect.go:/^func.dcommontype and // ../reflect/type.go:/^type.rtype. // ../internal/reflectlite/type.go:/^type.rtype. type _type struct { size uintptr ptrdata uintptr // size of memory prefix holding all pointers hash uint32 tflag tflag align uint8 fieldAlign uint8 kind uint8 // function for comparing objects of this type // (ptr to object A, ptr to object B) -> ==? equal func(unsafe.Pointer, unsafe.Pointer) bool // gcdata stores the GC type data for the garbage collector. // If the KindGCProg bit is set in kind, gcdata is a GC program. // Otherwise it is a ptrmask bitmap. See mbitmap.go for details. gcdata *byte str nameOff ptrToThis typeOff }
sizeptrdatahashequalgcdata
iface 结构体

type iface struct { tab *itab data unsafe.Pointer }
同样包含两个字段,只有第一个字段不一样,这里是tab。iface 同 eface 一样,也是共占用16字节。
我们看下 的数据结构
// layout of Itab known to compilers // allocated in non-garbage-collected memory // Needs to be in sync with // ../cmd/compile/internal/gc/reflect.go:/^func.dumptabs. type itab struct { inter *interfacetype _type *_type hash uint32 // copy of _type.hash. Used for type switches. _ [4]byte fun [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter. }
runtime.itab
hashinterfaceruntime._typefun
funfun[0]0_type
interinterfacetype
type interfacetype struct { typ _type pkgpath name mhdr []imethod }
typpkgpathmhdr
interfacetpearraytypemaptypechartypechantypeslicetype
_type
type arraytype struct { typ _type elem *_type slice *_type len uintptr } type chantype struct { typ _type elem *_type dir uintptr } type slicetype struct { typ _type elem *_type } type functype struct { typ _type inCount uint16 outCount uint16 } type ptrtype struct { typ _type elem *_type } type structtype struct { typ _type pkgPath name fields []structfield } type structfield struct { name name typ *_type offsetAnon uintptr }
这些数据类型的结构体定义,是反射实现的基础。
imethtod
type imethod struct { name nameOff ityp typeOff }
nameOfftypeOff
类型转换
值接收者指针接收者这里
convXXXtypedmemmove
下面我们从一个示例中来确认这一点。
package main import ( "fmt" ) // 定义有方法的接口,对应的是 iface 结构体 type MyInterface interface { Print() } type MyStruct struct{} func (ms MyStruct) Print() {} func main() { // 空接口,对应 eface a := 1 var x interface{} = a // 非空方法的接口,对应 iface var b MyStruct var y MyInterface = b fmt.Println(x, y) }
执行命令
go tool compile -S main.go
从输出结果中可以看到调用的 convXXX 函数。
类型断言TODO
参考资料