【go原始碼分析】go原始碼之interface原始碼分析
阿新 • • 發佈:2019-01-04
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)