42

Go语言interface底层实现

 4 years ago
source link: https://studygolang.com/articles/20180?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Go的interface源码在Golang源码的 runtime 目录中。

Go在不同版本之间的interface结构可能会有所不同,但是,整体的结构是不会改变的,此文章用的Go版本是1.11。

Go的interface是由两种类型来实现的: ifaceeface

其中, iface 表示的是包含方法的interface,例如:

type Person interface {
    Print()
}

eface 代表的是不包含方法的interface,即

type Person interface {}

或者

var person interface{} = xxxx实体

eface

eface 的具体结构是:

Vz2myeQ.jpg!web

在这里插入图片描述

一共有两个属性构成,一个是类型信息 _type ,一个是数据信息。

其中, _type 可以认为是Go语言中所有类型的公共描述,Go语言中几乎所有的数据结构都可以抽象成 _type ,是所有类型的表现,可以说是万能类型,

data

是指向具体数据的指针。

type 的具体代码为:

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
}

eface 的整体结构是:

vu2qemM.jpg!web

在这里插入图片描述

对于没有方法的interface赋值后的内部结构是怎样的呢?

可以先看段代码:

import (
    "fmt"
    "strconv"
)

type Binary uint64

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

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

ZBFzqmi.jpg!web

在这里插入图片描述

对于将不同类型转化成 type 万能结构的方法,是运行时的 convT2E 方法,在 runtime 包中。

以上,是对于没有方法的接口说明。

对于包含方法的函数,用到的是另外的一种结构,叫 iface

iface

所有包含方法的接口,都会使用 iface 结构。包含方法的接口就是一下这种最常见,最普通的接口:

type Person interface {
    Print()
}

iface 的源代码是:

type iface struct {
    tab  *itab
    data unsafe.Pointer
}

iface 的具体结构是:

IvUzMva.png!web

在这里插入图片描述

itabiface 不同于 eface 比较关键的数据结构。其可包含两部分:一部分是确定唯一的包含方法的interface的具体结构类型,一部分是指向具体方法集的指针。

具体结构为:

3Eviiin.png!web

在这里插入图片描述

属性 itab

的源代码是:

type itab struct {
    inter *interfacetype //此属性用于定位到具体interface
    _type *_type //此属性用于定位到具体interface
    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 类似于 _type ,其作用就是interface的公共描述,类似的还有 maptypearraytypechantype ...其都是各个结构的公共描述,可以理解为一种外在的表现信息。 interfacetype 源码如下:

type interfacetype struct {
    typ     _type
    pkgpath name
    mhdr    []imethod
}
type imethod struct {
    name nameOff
    ityp typeOff
}

iface 的整体结构为:

aMVfIzM.jpg!web

在这里插入图片描述

对于含有方法的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)
}

首先,要知道代码运行结果为:200。

其次,了解到 fmt.Stringer 是一个包含 String 方法的接口。

type Stringer interface {
    String() string
}

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

vQVRZjI.jpg!web

在这里插入图片描述

对于将不同类型转化成itable中 type(Binary) 的方法,是运行时的 convT2I 方法,在 runtime 包中。

更多精彩内容,请关注我的微信公众号 互联网技术窝 或者加微信共同探讨交流:

aYFbM3z.jpg!web

image


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK