Go-接口实现原理 Go-接口实现原理

Go-接口实现原理

接口的底层结构

efaceiface

  efaceiface都是描述接口的数据结构,区别在于iface描述的接口包含方法、而eface描述的接口不包含方法

eface的数据结构

type eface struct {
    _type *_type                    //实体类型
    data  unsafe.Pointer    //具体的值
}

eface主要包含实体类型_type指针和指向具体值的指针data

  • _type描述了实体类型包括内存大小、对齐方式等等,所有类型均可解释为_type
  • data存储了数据的指针,即使是对于数字、字符串这样的字面值也是通过额外分配空间取指针的

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.
}

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

iface中存储的是一个itab指针和一个指向数据的指针,itab中:

  • _type依旧描述了实体类型包括内存大小、对齐方式等数据
  • inter则描述了接口自身的信息,其中的mhdr字段包含了接口所定义的方法
  • fun其实是一个动态数组,虽然声明时是固定大小为1,但在使用时会直接通过fun指针获取其中的数据,类似于c语言中的不定长结构体

值接收者和指针接受者

package main

type Person struct {
    age int
}
func (p Person) howOld() int {
    return p.age
}
func (p *Person) growUp() {
    p.age += 1
}

func  main() {
    p1 := Person{}
    p2 := &Person{}
    p1.howOld()
    p1.growUp()

    p2.howOld()
    p2.growUp()
}

howOld是值接收者、growUp是指针接者,对于普通的函数调用而言在使用者go内部做了兼容可以互相调用

但是在接口中这是不兼容的,指针类型、值类型赋值给接口其生成的函数集是不一样的

函数集

值类型 函数集
(T) (t T)
指针(*T) (t T)(t *T)

原因很简单:对于有一些值是无法取到指针的,比如数字、字符串的字面值

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章