作者:得物技术

出处:https://segmentfault.com/a/1190000037749103

interface

In Object-oriented programming, a protocol or interface is a common means for unrelated Object (computer science) to communicate with each other. These are definitions of Method (computer programming) and values which the objects agree upon in order to co-operate. —— wiki

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(1)

0 interface是什么

在wiki中是这样定义的,interface和protocol类似,都是双方为了交流而作出的约定。

直接拿这套定义去理解golang中的interface可能难以理解,那么可以换种说法,即interface就像包饺子。

具体类型就像饺子馅,而预先定义的接口则就是饺子皮,也就是对具体类型进行了一层封装后,放入桌上(itabTable),随需随拿。最后吃的仍然是馅。

(真正使用的仍然是接口中包着的具体类型方法)

01.为什么要使用interface

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(2)

1.1 写一个通用的函数

在golang中不支持泛型,如果不使用interface的话,需要考虑不同类型的入参,复制粘贴n份,累得慌。

而有了interface之后,各种类型都能封装成interface,因此间接的实现了泛型编程,能够用来写接受多种类型入参的函数。

这一点可以利用来做单元测试 (mock入参) ,以及各服务之间的解偶 (比如只提供一个redis的增删改查接口,实现层可随意替换实现方式不影响业务) 。

1.2 隐藏具体实现

用户只能使用interface提供的方法,而具体的实现细节则不需要暴露。(典型案例context.Context)

1.3 提供插入点

有点像java的静态代理,就是在调用函数的时候,在前面做点别的事情。

举个例子就是在http请求之前加header的实现:

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(3)

02.interface的结构

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(4)

interface存在两种interface类型,eface和iface。2.1 eface

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(5)

eface顾名思义 empty interface,没有定义方法的interface底层结构即为eface。

eface只有_type以及指向数据(拷贝)的指针。

2.2 iface

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(6)

定义了方法的interface底层结构为iface。

iface则还有定义接口方法,因此有有一个tab属性以及指向数据(拷贝)的指针。

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(7)

03.itabTable的设计

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(8)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(9)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(10)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(11)

3.1 什么是itabTable

golang有一个itabTable哈希表,即利用空间换时间的思路,存放所有的itab,具体实现方式则通过一个数组(entries)实现。

3.2 如何对itab进行哈希

取itab中的接口类型与实际类型,分别哈希后取异或。

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(12)

3.3 itabTable哈希表的寻址方式——(二次寻址法)

itabTable作为一个哈希表,插入和读取肯定不可能是每次遍历整个数组,这样非常耗费性能。

因此go中itabTable使用的是quadratic probing。

公式为**h(i) = h0 i(i 1)/2 mod 2^k

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(13)

h(i):目标位置

h0:起点,也就是一开始 将itab哈希之后的值 。(在这里对itab哈希的实现是通过将interfacetype和itab分别哈希之后异或获得)

i(i 1)/2:用于防止哈希冲突**,其实就是趋向于1 2 3 4 5 6...的函数表达式,在实现中是一个for循环,不断增加偏移量,比如一开始a 1,如果bucket已被占位或不是目标内容,则下一次找a 1 2的位置,还不是就a 1 2 3。为了防止一直递增超过哈希表(数组)的大小,所以加一个mod 2^k(mod数组的长度)

其实也就是一种 二次寻址法的实现

04.itabTable的增与删

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(14)

4.1 itab的初始化——init方法itab需要初始化之后才能插入itabTable。

遍历接口类型与具体类型比较具体类型是否实现了所有接口类型, 理论上时间复杂度为O(n^2)。

但是实际上因为接口类型与具体类型的插入都是按照字典序排序的,因此实际上 时间复杂度为O(mn) ,使用双指针遍历即可。

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(15)

4.2 插入itab至itabTable(add方法)

itab使用接口类型(interfaceType)以及具体类型(_type)初始化之后,就能将itab放置与itabTable。

使用的插入方法正是之前的 二次寻址法

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(16)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(17)

4.3 在itabTable中寻找itab(find方法)

在itabTable中根据接口类型以及具体类型寻找itab。

使用的搜索模式也是 二次寻址法

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(18)

05.汇编验证

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(19)

代码皆不可信,我们再用汇编来证实一下以上的思路。

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(20)

汇编代码:

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(21)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(22)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(23)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(24)

06.思考

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(25)

全文读至此,应该能读懂runtime.convI2I方法了

有兴趣的可以根据上文的内容,解读一下上面汇编中使用的方法。

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(26)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(27)

从底层深入go的基础模型是什么(从底层深入Go的基础模型)(28)

END

作者:得物技术

出处:https://segmentfault.com/a/1190000037749103

,