关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » UI前端 »Go语言Interface机制解析

    Go语言Interface机制解析

    2015-03-04 00:00:00 出处:YouYaInsist的博客
    分享

    前几日一朋友在学GO,问了我一些interface机制的问题。试着解释发现自己也不是太清楚,所以今天下午特意查了资料和阅读GO的源码(基于go1.4),整理出了此文。假如有错误的地方还望指正。

    GO语言的interface是我比较喜欢的特性之一。interface与struct之间可以相互转换,struct不需要像JAVA在源码中显示说明实现了某个接口,可以通过约定的形式,隐式的转换到interface,还可以在运行时查询接口类型,这样有种用动态语言写代码的感觉,但是又可以在编译时进行检查,捕捉一些明显的类型不匹配的错误。

    type Stringer interface {
        String() string
    }
    
    type S struct {
         i int
    }
    
    func (s *S) String() string {
        return fmt.Sprintf("%d", s.i)
    }
    
    func Print(s Stringer) {
        println(s.String())
    }
    
    func DynamicPrint(any interface{}) {
       if s, ok := any.(Stringer); ok {
           Print(s)
       }
    }
    
    func main() {
       var s S
       s.i = 123456789
       Print(&s)
       DynamicPrint(&s)
    }

    如上面的代码所示,类型S没有显示的实现Stringer接口,但是它的方法列表符合Stringer接口,所以可以转换为Stringer接口使用。

    那么,GO语言的interface机制到底是如何实现的呢?

    interface value

    上述代码中函数Print的参数是一个Stringer接口,也就是Stringer的一个对象实例。这个对象实例叫做interface value。它的数据结构如下:

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

    其中tab字段类似于C++的vptr,tab中包含了对应的方法数组,除此之外还保存了实现该接口的类型元数据。data是对应的实现该接口的类型的实例指针。

    itab数据结构如下:

    type itab struct {
        inter     *interfacetype
        _type     *_type
        link      *itab
        bad       int32
        unused    int32
        fun       [0]unsafe.Pointer
    }

    其中inter字段表示这个interface value所属的接口元信息,_type字段表示具体实现类型的元信息,fun字段表示该interface的方法数组。link,bad,unused字段暂时不关心。

    当我们在GO代码中调用一个接口的方法时,操作类似如下: s.tab->fun[0](s.data)。调用开销还是很小的。

    Itab的生成方式

    一个自定义的结构体可以实现某个接口,然后可以隐式的转换到对应的接口。这种操作有点像C++的派生类转换为基类一样,这个操作是一个运行时绑定过程。而GO语言的interface机制还有一些其他特性:比如一个具体类型可以实现N多方法,但是只有其中某几个或者全部都满足某个接口,而此时,不可能把所有的方法都放到Itab中,这就意味着需要在绑定过程中剔除某些不需要的方法。

    GO编译器会在编译时会为每个自定义结构体和interface类型生成一个类型元数据,用来描述这个类型的名称,类型的HASH值,类型的方法列表,方法列表中还包括了方法的名称。而在一个自定义结构体转换到一个interface类型时,GO编译器会生成代码,使其在运行时计算Itab,完成动态绑定方法的需求。这个计算Itab的过程相对来说比较简单,因为GO编译器生成的类型元数据中包含了所有的方法名称和地址,那么在一个结构体实例转换为interface value时,只需要把interface的方法列表作为基,方法名和方法类型作为KEY,去结构体元数据中查找对应的方法即可。

    GO的runtime库中对Itab的查找过程做了优化,由O(ni * nt)复杂度变为O(ni + nt)。依据是一个自定义结构体实现的方法一定是大于或等于某个具体interface的方法集的。所以可以事先把所有的方法按照名字从小到大排序,然后在匹配到一个方法后,可以在下次查找时使用上次的索引值。

    除此之外,GO编译器为了减少每次不必要的Itab,还增加了一个对应的itab的缓存。你可以编译一个GO程序,然后反编译后可以查看到一个类似go_itab__main_S_main_Stringer名称的变量。在每次一个结构体转换到一个interface之前都会检查这个缓存是否有效,有效就使用。这个检查也只是一个cmp指令而已。

    还有在GO运行时库里,为了减少每次的Itab实现,还做了相应的优化。内部实现了一个HASH表,保存了每个具体结构体到interface转换生成的Itab实例。代码可以在gosrcruntimeiface.go getitab函数中看到。

    interface{}的特殊处理

    interface{}在GO中是一个特殊的内建类型,类似于C/C++中的void*,但是包含了类型信息。所以你可以把任意的数据转换到interface{},然后通过type assert从interface{}获取原有的数据。但是正如你所见,interface{}没有方法,那么也就是说,它不需要iface中的itab,因为不需要方法绑定。针对此,做了特殊修改,iface中的tab字段类型由itab指针变为了对应的具体实现类型的类型元数据指针。在GO源码中,interface{}对象的类型原型如下:

    type eface struct {
        _type *_type
        data  unsafe.Pointer
    }

    eface是empty interface的缩写。

    其他

    在GO的源码iface.go中,还可以看到很多函数比如叫assertE2E,assertE2I,assertE2T等,这些函数就是对应的type assert的具体实现函数。E表示eface,I表示iface,T表示自定义的结构体或者基于内建类型创造出的类型。代码都比较简单,不在叙述了。

    总结

    想理解interface机制的实现,只需要理解类型元数据以及动态绑定过程。其中要还区分interface value,也就是内部的iface结构体。因此引出了Itable的概念。整体来说不是太复杂,数据结构也比较简单,假如你有时间的话,也可以自己看下GO的源码。

    参考

    GO源码(gosrcruntimeiface.go)《Go Data Structures: Interfaces》《Go Interfaces》

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    hiberfil.sys文件可以删除吗?了解该文件并手把手教你删除C盘的hiberfil.sys文件

    Window 10和 Windows 11哪个好?答案是:看你自己的需求

    盗版软件成公司里的“隐形炸弹”?老板们的“法务噩梦” 有救了!

    帝国CMS7.5编辑器上传图片取消宽高的三种方法

    帝国cms如何自动生成缩略图的实现方法

    Windows 12即将到来,将彻底改变人机交互

    帝国CMS 7.5忘记登陆账号密码怎么办?可以phpmyadmin中重置管理员密码

    帝国CMS 7.5 后台编辑器换行,修改回车键br换行为p标签

    Windows 11 版本与 Windows 10比较,新功能一览

    Windows 11激活产品密钥收集及专业版激活方法

    IT头条

    无线路由大厂 TP-Link突然大裁员:补偿N+3

    02:39

    Meta 千万美金招募AI高级人才

    00:22

    更容易爆炸?罗马仕充电宝被北京多所高校禁用,公司紧急回应

    17:19

    天衍”量子计算云平台,“超算+量算” 告别“算力孤岛时代”

    18:18

    华为Pura80系列新机预热,余承东力赞其复杂光线下的视频拍摄实力

    01:28

    技术热点

    MySQL基本调度策略浅析

    MySQL使用INSERT插入多条记录

    SQL Server高可用的常见问题

    3D立体图片展示幻灯片JS特效

    windows 7上网看视频出现绿屏的原因及解决方法

    windows 7 64位系统的HOSTS文件在哪里?想用它加快域名解析

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。