原文鏈接 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中,我們看下源碼
1 2 3 4
|
type eface struct { _type *_type data unsafe.Pointer }
|
可以看到eface包含兩個結構,一個是_type類型指針,一個是unsafe包的Pointer變量
繼續追蹤Pointer
1 2
|
type Pointer *ArbitraryType type ArbitraryType int
|
可以看出Pointer實際上是int類型的指針。我們再看看_type類型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
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命令生成可執行文件,再用匯編查看下源碼。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
package main
import "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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
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) efacedemo.go:18 0x49003e 488d442430 LEAQ 0 |