Go interface源码解析-note

2023-01-30  本文已影响0人  robertzhai

interface底层使用2个struct表示:eface和iface , 位置 src/runtime/runtime2.go

image.png
image.png
// 有方法的接口 iface 非空接口
type iface struct {
    tab  *itab
    data unsafe.Pointer //指向原始数据指针
}
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.
}
// runtime/type.go
// 非空接口类型,接口定义,包路径等。
type interfacetype struct {
   typ     _type
   pkgpath name
   mhdr    []imethod      // 接口方法声明列表,按字典序排序
}



// 接口的方法声明,一种函数声明的抽象
// 比如:func Print() error
type imethod struct {
   name nameOff          // 方法名
   ityp typeOff                // 描述方法参数返回值等细节
}

type nameOff int32
type typeOff int32
method 存的是func 的声明抽象,而 itab 中的 fun 字段才是存储 func 的真实切片。


// 没有方法的接口 eface 空接口定义
type eface struct {
    _type *_type //类型信息
    data  unsafe.Pointer  //数据信息,指向数据指针
}
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
}

没有方法的interface赋值后内部结构

import (
    "fmt"
    "strconv"
)

type Binary uint64

func main() {
    b := Binary(200)
    any := (interface{})(b)
    fmt.Println(any)
}

输出200,赋值后的结构图是这样的


image.png

iface 非空接口

非空接口(iface)本身除了可以容纳满足其接口的对象之外,还需要保存其接口的方法,因此除了data字段,iface通过tab字段描述非空接口的细节,包括接口方法定义,接口方法实现地址,接口所指类型等。iface是非空接口的实现,而不是类型定义,iface的真正类型为interfacetype,其第一个字段仍然为描述其自身类型的_type字段。


image.png

含有方法的interface赋值后的内部结构

package main

import (
    "fmt"
    "strconv"
)

type Binary uint64
func (i Binary) String() string {
    return strconv.FormatUint(i.Get(), 10)
}

func (i Binary) Get() uint64 {
    return uint64(i)
}

func main() {
    b := Binary(200)
    any := fmt.Stringer(b)
    fmt.Println(any)
}

赋值后接口Stringer的内部结构为


image.png

ref

上一篇下一篇

猜你喜欢

热点阅读