@@ -142,16 +142,99 @@ func CreateOrder(order OrderStruct) {
142142
143143### eface 适用场景
144144
145- ### eface 实现原理
145+ 举个标准库里的例子:
146+
147+ ``` go
148+ func Slice (slice interface {}, less func (i, j int ) bool )
149+ ```
150+
151+ 标准库的 container package,因为不知道用户会在 container 中存储什么类型,所以大部分 API 也是用 interface{} 的。
152+
153+ 除了标准库,我们在 fmt.Print 系列和 json.Unmarshal 中也会见到 interface{}。
154+
155+ ``` go
156+ func Println (a ...interface {}) (n int , err error )
157+ ```
158+
159+ ```go
160+ func Unmarshal(data []byte, v interface{}) error
161+ ```
162+
163+ 总结一下,使用 interface 主要是我们在不知道用户的输入类型信息的前提下,希望能够实现一些通用数据结构或函数。这时候便会将空 interface{} 作为函数的输入/输出参数。在其它语言里,解决这种问题一般使用泛型。
146164
147165## 类型转换
148166
149167### 普通类型转换为 eface
150168
151- ### 普通类型转换为 iface
169+ ``` go
170+ 1 package main
171+ 2
172+ 3 var i interface {}
173+ 4
174+ 5 func main () {
175+ 6 var y = 999
176+ 7 i = y
177+ 8 var x = i.(int )
178+ 9 println (x)
179+ 10 }
180+ ```
181+
182+ 老规矩,看汇编知一切,主要是第 7 行:
183+
184+ ``` go
185+ 0x0021 00033 (interface .go :7 ) MOVQ $999 , (SP) // 把 999 作为参数挪到栈底
186+ 0x0029 00041 (interface .go :7 ) CALL runtime.convT64 (SB) // 以 999 作为参数调用 runtime.convT64,内部会为该变量在堆上分配额外空间,并返回其地址
187+ 0x002e 00046 (interface .go :7 ) MOVQ 8 (SP), AX // 返回值移动到 AX 寄存器
188+ 0x0033 00051 (interface .go :7 ) LEAQ type .int (SB), CX // 将 type.int 值赋值给 CX 寄存器
189+ 0x003a 00058 (interface .go :7 ) MOVQ CX , " " .i (SB) // 将 type.int 赋值给 eface._type
190+ 0x004a 00074 (interface .go :7 ) MOVQ AX , " " .i +8 (SB) // 将数据 999 的地址赋值给 eface.data
191+ ```
192+
193+ 还是比较简单的。
152194
153195### eface 转换为普通类型
154196
197+ 空接口转成普通类型,其实就是断言。我们继续使用上面的 demo:
198+
199+ ``` go
200+ 1 package main
201+ 2
202+ 3 var i interface {}
203+ 4
204+ 5 func main () {
205+ 6 var y = 999
206+ 7 i = y
207+ 8 var x = i.(int ) // 这次关注断言的实现
208+ 9 println (x)
209+ 10 }
210+ ```
211+
212+ 看看第 8 行的输出:
213+
214+ ``` go
215+ 0x0033 00051 (interface .go :7 ) LEAQ type .int (SB), CX // 在第 7 行把 type.int 搬到 CX 寄存器了,注意下面要用到
216+ .....
217+ 0x0051 00081 (interface .go :8 ) MOVQ " " .i +8 (SB), AX // AX = eface.data
218+ 0x0058 00088 (interface .go :8 ) MOVQ " " .i (SB), DX // DX = eface._type
219+ 0x005f 00095 (interface .go :8 ) CMPQ DX , CX // 比较 _type 和 type.int 是否相等
220+ 0x0062 00098 (interface .go :8 ) JNE 161 // 如果不等,说明断言失败,跳到 161 位置,开始执行 panic 流程
221+ 0x0064 00100 (interface .go :8 ) MOVQ (AX), AX // 把 AX 地址里的内容搬到 AX 寄存器,现在 AX 里存的是 999 了
222+ 0x0067 00103 (interface .go :8 ) MOVQ AX , " " .x +24 (SP) // 将 999 赋值给变量 x
223+
224+ // 下面这部分是实现 panic 的,不是我们的重点
225+ 0x00a1 00161 (interface .go :8 ) MOVQ DX , (SP)
226+ 0x00a5 00165 (interface .go :8 ) MOVQ CX , 8 (SP)
227+ 0x00aa 00170 (interface .go :8 ) LEAQ type .interface {}(SB), AX
228+ 0x00b1 00177 (interface .go :8 ) MOVQ AX , 16 (SP)
229+ 0x00b6 00182 (interface .go :8 ) CALL runtime.panicdottypeE (SB)
230+ 0x00bb 00187 (interface .go :8 ) XCHGL AX , AX
231+ 0x00bc 00188 (interface .go :8 ) NOP
232+ ```
233+
234+ 也挺简单的,这里我们用的是 int 来进行实验,对于稍微复杂一些的复合类型,也只是多出了一些步骤,本质上没有什么区别,感兴趣的读者可以自行研究。
235+
236+ ### 普通类型转换为 iface
237+
155238### iface 转换为普通类型
156239
157240### 类型转换图
0 commit comments