1. 程式人生 > >【go原始碼分析】go原始碼之interface原始碼分析

【go原始碼分析】go原始碼之interface原始碼分析

  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)