数据类型
接口的定义
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
参考资料