共计 2025 个字符,预计需要花费 6 分钟才能阅读完成。
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
0 interface 是什么
在 wiki 中是这样定义的,interface 和 protocol 相似,都是单方为了交换而作出的约定。
间接拿这套定义去了解 golang 中的 interface 可能难以了解,那么能够换种说法,即 interface 就像包饺子。
具体类型就像饺子馅,而事后定义的接口则就是饺子皮,也就是对具体类型进行了一层封装后,放入桌上(itabTable),随需随拿。最初吃的依然是馅。
(真正应用的依然是接口中包着的具体类型办法)
01.
为什么要应用 interface
1.1 写一个通用的函数
在 golang 中不反对泛型,如果不应用 interface 的话,须要思考不同类型的入参,复制粘贴 n 份,累得慌。
而有了 interface 之后,各种类型都能封装成 interface,因而间接的实现了泛型编程,可能用来写承受多种类型入参的函数。
这一点能够利用来做单元测试 (mock 入参),以及各服务之间的解偶 (比方只提供一个 redis 的增删改查接口,实现层可随便替换实现形式不影响业务)。
1.2 暗藏具体实现
用户只能应用 interface 提供的办法,而具体的实现细节则不须要裸露。(典型案例 context.Context)
1.3 提供插入点
有点像 java 的动态代理,就是在调用函数的时候,在后面做点别的事件。
举个例子就是在 http 申请之前加 header 的实现:
02.
interface 的构造
interface 存在两种 interface 类型,eface 和 iface。
2.1 eface
eface 顾名思义 empty interface,没有定义方法的 interface 底层构造即为 eface。
eface 只有_type 以及指向数据 (拷贝) 的指针。
2.2 iface
定义了办法的 interface 底层构造为 iface。
iface 则还有定义接口办法,因而有有一个 tab 属性以及指向数据 (拷贝) 的指针。
03.
itabTable 的设计
3.1 什么是 itabTable
golang 有一个 itabTable 哈希表,即利用空间换工夫的思路,寄存所有的 itab,具体实现形式则通过一个数组 (entries) 实现。
3.2 如何对 itab 进行哈希
取 itab 中的接口类型与理论类型,别离哈希后取异或。
3.3 itabTable 哈希表的寻址形式
——(二次寻址法)
itabTable 作为一个哈希表,插入和读取必定不可能是每次遍历整个数组,这样十分消耗性能。
因而 go 中 itabTable 应用的是 quadratic probing。
公式为 **h(i) = h0 + i(i+1)/2 mod 2^k
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 的增与删
4.1 itab 的初始化——init 办法
itab 须要初始化之后能力插入 itabTable。
遍历接口类型与具体类型 比拟具体类型是否实现了所有接口类型,实践上工夫复杂度为 O(n^2)。
然而实际上因为接口类型与具体类型的插入都是依照字典序排序的,因而实际上 工夫复杂度为 O(mn),应用双指针遍历即可。
4.2 插入 itab 至 itabTable(add 办法)
itab 应用接口类型 (interfaceType) 以及具体类型 (_type) 初始化之后,就能将 itab 搁置与 itabTable。
应用的插入方法正是之前的 二次寻址法。
4.3 在 itabTable 中寻找 itab(find 办法)
在 itabTable 中依据接口类型以及具体类型寻找 itab。
应用的搜寻模式也是 二次寻址法。
05.
汇编验证
代码皆不可信,咱们再用汇编来证实一下以上的思路。
汇编代码:
06.
思考
全文读至此,应该能读懂 runtime.convI2I 办法了
有趣味的能够依据上文的内容,解读一下下面汇编中应用的办法。
END
文|【无线平台】李晨毅
关注咱们
分享技术好文