首页 / GO / Golang Interface 解析
Golang Interface 解析
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Golang Interface 解析,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含10188字,纯文字阅读大概需要15分钟。
内容图文
![Golang Interface 解析](/upload/InfoBanner/zyjiaocheng/1318/7995862bc291419f945a32b2c92758e1.jpg)
转自 https://zhuanlan.zhihu.com/p/27652856
先看一段代码:
1 |
func (x interface{}) { |
上面的例子的输出结果如下
1 |
$ go run test_interface.go |
可能你会感觉奇怪,为什么会是 non-empty inerface,那么继续往下看,你就会知道答案。
interface 底层结构
根据 interface 是否包含有 method,底层实现上用两种 struct 来表示:iface 和 eface。eface表示不含 method 的 interface 结构,或者叫 empty interface。对于 Golang 中的大部分数据类型都可以抽象出来 _type 结构,同时针对不同的类型还会有一些其他信息。
1 |
type eface struct { |
iface 表示 non-empty interface 的底层实现。相比于 empty interface,non-empty 要包含一些 method。method 的具体实现存放在 itab.fun 变量里。如果 interface 包含多个 method,这里只有一个 fun 变量怎么存呢?这个下面再细说。
1 |
type iface struct { |
我们使用实际程序来看一下。
1 |
package main |
查看汇编代码。
1 |
$ go build -gcflags '-l' -o interface11 interface11.go |
代码 17 行 var y interface{} = x 调用了函数 runtime.convT2E,将 int 类型的 x 转换成 empty interface。代码 19 行 var t MyInterface = s 将 MyStruct 类型转换成 non-empty interface: MyInterface。
1 |
func convT2E (t *_type, elem unsafe.Pointer) (e eface) { |
看上面的函数原型,可以看出中间过程编译器将根据我们的转换目标类型的 empty interface 还是 non-empty interface,来对原数据类型进行转换(转换成 <_type, unsafe.Pointer> 或者 <itab, unsafe.Pointer>)。这里对于 struct 满不满足 interface 的类型要求(也就是 struct 是否实现了 interface 的所有 method),是由编译器来检测的。
itab
iface 结构中最重要的是 itab 结构。itab 可以理解为 pair<interface type,="" concrete="" type=""> 。当然 itab 里面还包含一些其他信息,比如 interface 里面包含的 method 的具体实现。下面细说。itab 的结构如下。
1 |
type itab struct { |
其中 interfacetype 包含了一些关于 interface 本身的信息,比如 package path,包含的 method。上面提到的 iface 和 eface 是数据类型(built-in 和 type-define)转换成 interface 之后的实体的 struc 大专栏 Golang Interface 解析t 结构,而这里的 interfacetype 是我们定义 interface 时候的一种抽象表示。
1 |
type interfacetype struct { |
_type 表示 concrete type。fun 表示的 interface 里面的 method 的具体实现。比如 interface type 包含了 method A, B,则通过 fun 就可以找到这两个 method 的具体实现。这里有个问题 fun 是长度为 1 的 uintptr 数组,那么怎么表示多个 method 呢?看一下测试程序。
1 |
package main |
看一下函数调用对应的汇编代码。
1 |
$ go build -gcflags '-l' -o interface8 interface8.go |
其中 0x18(SP) 对应的 itab 的地址。fun 在 x86-64 机器上对应 itab 内的地址偏移为 8+8+8+4+4 = 32 = 0x20,也就是 0x20(AX) 对应的 fun 的值,此时存放的 AWK 函数地址。然后 0x28(AX) = &Hello,0x30(AX) = &Print,0x38(AX) = &World。对的,每次函数是按字典序排序存放的。
我们再来看一下函数地址究竟是怎么写入的?首先 Golang 中的 uintptr 一般用来存放指针的值,这里对应的就是函数指针的值(也就是函数的调用地址)。但是这里的 fun 是一个长度为 1 的 uintptr 数组。我们看一下 runtime 包的 additab 函数。
1 |
func additab(m *itab, locked, canfail bool) { |
上面的代码的意思是在 fun[0] 的地址后面依次写入其他 method 对应的函数指针。熟悉 C++ 的同学可以类比 C++ 的虚函数表指针来看。
剩下的还有 bad,link,inhash。其中 bad 是一个表征 itab 状态的变量。而这里的 link 是 *itab 类型,是不是表示 interface 的嵌套呢?并不是,interface 的嵌套也是把 method 平铺而已。link 要和 inhash 一起来说。在 runtime 包里面有一个 hash 表,通过 hash[hashitab(interface_type, concrete_type)] 可以取得 itab,这是出于性能方面的考虑。主要代码如下,这里就不再赘述了。
1 |
const ( |
3. Type Assertion
我们知道使用 interface type assertion (中文一般叫断言) 的时候需要注意,不然很容易引入 panic。
1 |
func do(v interface{}) { |
这个过程体现在下面的几个函数上。
1 |
// The assertXXX functions may fail (either panicking or returning false, |
4. 总结
从某种意义上来说,Golang 的 interface 也是一种多态的体现。对比其他支持多态特性的语言,实现还是略有差异,很难说谁好谁坏。
原文:https://www.cnblogs.com/lijianming180/p/12032143.html
内容总结
以上是互联网集市为您收集整理的Golang Interface 解析全部内容,希望文章能够帮你解决Golang Interface 解析所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。