数据类型
接口的定义
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 结构体

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

参考资料