前言
关于接口的底层原理剖析点击Golang底层原理剖析之类型系统,接口与类型断言
interface
- interface的两种类型 - 数据结构的interface,侧重于类型;面向对象中接口定义的interface,侧重于方法的声明
- 了解interface的底层定义 - eface和iface,都分为两个部分:类型与数据
- iface底层对类型匹配进行了优化 - map+mutex组合
源码
package main
import (
"fmt"
)
type Dog interface {
Hi()
}
type Dog1 struct{}
func (d Dog1) Hi() {}
type Dog2 struct{}
func (d Dog2) Hi() {}
/*
查看汇编,了解调用:
1. go build -gcflags '-l' -o if main.go interface.go
2. go tool objdump -s "main\.dataInterface" if
(汇编会因平台不同,调用结果会不一样)调用了 CALL runtime.XXX
对应代码在runtime/iface.go下,在这里,我们看到了interface的两个核心结构 eface 和 iface,分别对应convT2E和convT2I
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}
其中data指向了具体保存数据的内存地址,为一个通用结构。而itab中嵌套了_type,比较复杂,我们先从简单的eface看起
*/
func dataInterface() {
var i interface{} = 1
fmt.Println(i)
// Tip: 类型定义,除非是100%确定成功,否则尽量用两个参数,否则会导致panic
v, ok := i.(string)
fmt.Printf(v, ok)
var d1 Dog1
var d2 Dog2
var dList = []Dog{d1, d2}
for _, v := range dList {
v.Hi()
}
}
/*
Tip: eface part,静态的数据结构
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
}
Tip: runtime/type.go 类型定义包含了go语言常见的类型,我们可以从 t.kind & kindMask 看到Go里支持的所有类型
*/
/*
Tip: iface part,面向对象中的interface
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.
}
Tip: interfacetype 为接口的定义方法集; _type保存了具体的类型;而具体的方法的地址都被保存在fun中,是一个数组
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
type imethod struct {
name nameOff
ityp typeOff
}
methods := (*[1 << 16]unsafe.Pointer)(unsafe.Pointer(&m.fun[0]))[:ni:ni]
Tip: interface的类型推断,依赖于一个 itabTable,即一个map+lock,将匹配成功的保存进来,下次可直接查询
*/