Go语言interface底层实现

RyuGou · · 449 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

Go的interface源码在Golang源码的``runtime``目录中。 Go在不同版本之间的interface结构可能会有所不同,但是,整体的结构是不会改变的,此文章用的Go版本是1.11。 Go的interface是由两种类型来实现的:``iface``和``eface``。 其中,``iface``表示的是包含方法的interface,例如: ``` type Person interface { Print() } ``` 而``eface``代表的是不包含方法的interface,即 ``` type Person interface {} ``` 或者 ``` var person interface{} = xxxx实体 ``` ## ``eface`` ``eface``的具体结构是: ![在这里插入图片描述](https://img-blog.csdn.net/20181001154956234?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 一共有两个属性构成,一个是类型信息``_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``的整体结构是: ![在这里插入图片描述](https://img-blog.csdn.net/20181002115553494?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 对于没有方法的interface赋值后的内部结构是怎样的呢? 可以先看段代码: ``` import ( "fmt" "strconv" ) type Binary uint64 func main() { b := Binary(200) any := (interface{})(b) fmt.Println(any) } ``` 输出200,赋值后的结构图是这样的: ![在这里插入图片描述](https://img-blog.csdn.net/20181003112324954?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 对于将不同类型转化成``type``万能结构的方法,是运行时的``convT2E``方法,在``runtime``包中。 以上,是对于没有方法的接口说明。 对于包含方法的函数,用到的是另外的一种结构,叫``iface`` # ``iface`` 所有包含方法的接口,都会使用``iface``结构。包含方法的接口就是一下这种最常见,最普通的接口: ``` type Person interface { Print() } ``` ``iface``的源代码是: ``` type iface struct { tab *itab data unsafe.Pointer } ``` ``iface``的具体结构是: ![在这里插入图片描述](https://img-blog.csdn.net/20181003131717652?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) ``itab``是``iface``不同于``eface``比较关键的数据结构。其可包含两部分:一部分是确定唯一的包含方法的interface的具体结构类型,一部分是指向具体方法集的指针。 具体结构为: ![在这里插入图片描述](https://img-blog.csdn.net/20181003132256438?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 属性 ``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的公共描述,类似的还有``maptype``、``arraytype``、``chantype``...其都是各个结构的公共描述,可以理解为一种外在的表现信息。``interfacetype``源码如下: ``` type interfacetype struct { typ _type pkgpath name mhdr []imethod } type imethod struct { name nameOff ityp typeOff } ``` ``iface``的整体结构为: ![在这里插入图片描述](https://img-blog.csdn.net/20181003132400412?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 对于含有方法的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``的内部结构为: ![在这里插入图片描述](https://img-blog.csdn.net/20181003134734346?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2k2NDQ4MDM4/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) 对于将不同类型转化成itable中``type(Binary)``的方法,是运行时的``convT2I``方法,在``runtime``包中。 参考文献: + 《Go in action》 + https://research.swtch.com/interfaces + https://juejin.im/entry/5a7d08d3f265da4e865a6200 #### 更多精彩内容,请关注我的微信公众号 ``互联网技术窝`` 或者加微信共同探讨交流: ![](https://i6448038.github.io/img/weichat/qrcode.jpg)

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:1006366459

449 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传