版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhonglinzhang/article/details/85772336
interface实现原理
类似于C++多态的实现,存在两种interface,一种是带有方法的interface实现(iface struct),一种是不带方法的interface实现(eface struct),
iface结构体
- tab:类似于C++的vptr,tab中包含了对应的方法数组,包含实现该接口的类型元数据
- data:实现该接口的类型的实例指针
type iface struct {
tab *itab
data unsafe.Pointer
}
eface结构体
无method结构
type eface struct {
_type *_type
data unsafe.Pointer
}
itab结构体
- inter:表示这个interface value所属的接口元信息
- _type:表示具体实现类型的元信息
- fun:表示该interface的方法数组
// 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.dumptypestructs.
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.
}
interfacetype结构体
定义 interface 的一种抽象,包括pkg path,method
type interfacetype struct {
typ _type
pkgpath name
mhdr []imethod
}
type imethod struct {
name nameOff
ityp typeOff
}
_type结构体
Go语言中某个数据类型的基本信息
数据类型占用的内存大小(size字段),数据类型的名称(nameOff字段)
// 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.
type _type struct {
size uintptr
ptrdata uintptr // size of memory prefix holding all pointers
hash uint32
tflag tflag
align uint8
fieldalign uint8
kind uint8
alg *typeAlg
// 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
}
gdb调试interface(eface无method)
$ cat no-method-interface.go
package main
type s1 struct {
a int64
b int64
}
func main() {
s := new(s1)
var i interface{}
i = s
_ = i
}
编译以及gdb调试如下代码,go build -gcflags '-l -N' no-method-interface.go
gdb no-method-interface调试,interface变量i结构为eflace只有两个字段_type与data
继续调试c
对于将interface转为其他类型实现路径go/src/runtime/iface.go,中convertT2EXXX这些函数实现,无method转换实现
调用mallocgc函数负责给eface结构中的data字段
// The conv and assert functions below do very similar things.
// The convXXX functions are guaranteed by the compiler to succeed.
// The assertXXX functions may fail (either panicking or returning false,
// depending on whether they are 1-result or 2-result).
// The convXXX functions succeed on a nil input, whereas the assertXXX
// functions fail on a nil input.
func convT2E(t *_type, elem unsafe.Pointer) (e eface) {
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2E))
}
if msanenabled {
msanread(elem, t.size)
}
x := mallocgc(t.size, t, true)
// TODO: We allocate a zeroed object only to overwrite it with actual data.
// Figure out how to avoid zeroing. Also below in convT2Eslice, convT2I, convT2Islice.
typedmemmove(t, x, elem)
e._type = t
e.data = x
return
}
func convT2E16(t *_type, val uint16) (e eface)
func convT2E32(t *_type, val uint32) (e eface)
func convT2E64(t *_type, val uint64) (e eface)
func convT2Estring(t *_type, elem unsafe.Pointer) (e eface)
func convT2Eslice(t *_type, elem unsafe.Pointer) (e eface)
func convT2Enoptr(t *_type, elem unsafe.Pointer) (e eface)
对于有method的interface,则调用形如convT2IXXX实现
func convT2I(tab *itab, elem unsafe.Pointer) (i iface) {
t := tab._type
if raceenabled {
raceReadObjectPC(t, elem, getcallerpc(), funcPC(convT2I))
}
if msanenabled {
msanread(elem, t.size)
}
x := mallocgc(t.size, t, true)
typedmemmove(t, x, elem)
i.tab = tab
i.data = x
return
}
func convT2I16(tab *itab, val uint16) (i iface)
func convT2I32(tab *itab, val uint32)
func convT2I64(tab *itab, val uint64) (i iface)
func convT2Istring(tab *itab, elem unsafe.Pointer) (i iface)
func convT2Islice(tab *itab, elem unsafe.Pointer) (i iface)
func convT2Inoptr(tab *itab, elem unsafe.Pointer) (i iface)
func convI2I(inter *interfacetype, i iface) (r iface)
对于断言的实现则为assertXXX实现函数
func assertI2I(inter *interfacetype, i iface) (r iface) {
tab := i.tab
if tab == nil {
// explicit conversions require non-nil interface value.
panic(&TypeAssertionError{nil, nil, &inter.typ, ""})
}
if tab.inter == inter {
r.tab = tab
r.data = i.data
return
}
r.tab = getitab(inter, tab._type, false)
r.data = i.data
return
}
func assertI2I2(inter *interfacetype, i iface) (r iface, b bool)
func assertE2I(inter *interfacetype, e eface) (r iface)
func assertE2I2(inter *interfacetype, e eface) (r iface, b bool)