原文链接 http://www.limerence2017.com/2019/09/24/golang14/#more
前文介绍过golang interface用法,本文详细剖析interface内部实现和细节。
empty interface实现细节
interface底层使用两种类型实现的,一个是eface,一个是iface。当interface中没有方法的时候,底层是通过eface实现的。 当interface包含方法时,那么它的底层是通过iface实现的。 对于iface和eface具体实现在go源码runtime2.go中,我们看下源码
1234
type eface struct { _type *_type data unsafe.Pointer}
可以看到eface包含两个结构,一个是_type类型指针,一个是unsafe包的Pointer变量 继续追踪Pointer
12
type Pointer *ArbitraryTypetype ArbitraryType int
可以看出Pointer实际上是int类型的指针。我们再看看_type类型
12345678910111213141516
type _type struct { size uintptr ptrdata uintptr
size 为该类型所占用的字节数量。 kind 表示类型的种类,如 bool、int、float、string、struct、interface 等。 str 表示类型的名字信息,它是一个 nameOff(int32) 类型,通过这个 nameOff,可以找到类型的名字字符串
eface结构总结图 eface 分两个部分, *_type 类型为实际类型转化为type类型的指针,data为实际数据。
具体类型如何转化为eface
我们写一段程序efacedemo.go,然后用gobuild命令生成可执行文件,再用汇编查看下源码。
1234567891011121314151617181920
package mainimport "fmt"type EmpInter interface {}type EmpStruct struct { num int}func main() { emps := EmpStruct{num: 1} var empi EmpInter empi = emps fmt.Println(empi) fmt.Println(emps)}
先用gcflags标记编译生成可执行文件efacedemo go build -gcflags “-l” -o efacedemo efacedemo.go 然后执行go tool objdump 将 可执行程序efacedemo中main包的main函数转为汇编代码 go tool objdump -s “main.main” efacedemo
1234567891011121314151617181920212223242526272829303132333435363738
efacedemo.go:12 0x48ffa0 65488b0c2528000000 MOVQ GS:0x28, CX efacedemo.go:12 0x48ffa9 488b8900000000 MOVQ 0(CX), CX efacedemo.go:12 0x48ffb0 483b6110 CMPQ 0x10(CX), SP efacedemo.go:12 0x48ffb4 0f86ae000000 JBE 0x490068 efacedemo.go:12 0x48ffba 4883ec48 SUBQ $0x48, SP efacedemo.go:12 0x48ffbe 48896c2440 MOVQ BP, 0x40(SP) efacedemo.go:12 0x48ffc3 488d6c2440 LEAQ 0x40(SP), BP efacedemo.go:16 0x48ffc8 48c7042401000000 MOVQ $0x1, 0(SP) efacedemo.go:16 0x48ffd0 e8fb89f7ff CALL runtime.convT64(SB) //注意这里调用runtime包的convT64函数 efacedemo.go:16 0x48ffd5 488b442408 MOVQ 0x8(SP), AX efacedemo.go:17 0x48ffda 0f57c0 XORPS X0, X0 efacedemo.go:17 0x48ffdd 0f11442430 MOVUPS X0, 0x30(SP) efacedemo.go:17 0x48ffe2 488d0d17c20100 LEAQ runtime.types+111104(SB efacedemo.go:17 0x48ffe9 48894c2430 MOVQ CX, 0x30(SP) efacedemo.go:17 0x48ffee 4889442438 MOVQ AX, 0x38(SP) efacedemo.go:17 0x48fff3 488d442430 LEAQ 0x30(SP), AX efacedemo.go:17 0x48fff8 48890424 MOVQ AX, 0(SP) efacedemo.go:17 0x48fffc 48c744240801000000 MOVQ $0x1, 0x8(SP) efacedemo.go:17 0x490005 48c744241001000000 MOVQ $0x1, 0x10(SP) efacedemo.go:17 0x49000e e8fd98ffff CALL fmt.Println(SB) efacedemo.go:18 0x490013 48c7042401000000 MOVQ $0x1, 0(SP) efacedemo.go:18 0x49001b e8b089f7ff CALL runtime.convT64(SB) //注意这里调用runtime包的convT64函数 efacedemo.go:18 0x490020 488b442408 MOVQ 0x8(SP), AX efacedemo.go:18 0x490025 0f57c0 XORPS X0, X0 efacedemo.go:18 0x490028 0f11442430 MOVUPS X0, 0x30(SP) efacedemo.go:18 0x49002d 488d0dccc10100 LEAQ runtime.types+111104(SB efacedemo.go:18 0x490034 48894c2430 MOVQ CX, 0x30(SP) efacedemo.go:18 0x490039 4889442438 MOVQ AX, 0x38(SP)