【go源码分析】go源码之interface源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 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)

猜你喜欢

转载自blog.csdn.net/zhonglinzhang/article/details/85772336