網站首頁 編程語言 正文
GoLang之iface 和 eface 的區別是什么?
iface
和eface
都是 Go 中描述接口的底層結構體,區別在于iface
描述的接口包含方法,而eface
則是不包含任何方法的空接口:interface{}
。
從源碼層面看一下:
type iface struct { tab *itab data unsafe.Pointer } type itab struct { inter *interfacetype _type *_type link *itab hash uint32 // copy of _type.hash. Used for type switches. bad bool // type does not implement interface inhash bool // has this itab been added to hash? unused [2]byte fun [1]uintptr // variable sized }
iface
內部維護兩個指針,tab
指向一個itab
實體, 它表示接口的類型以及賦給這個接口的實體類型。data
則指向接口具體的值,一般而言是一個指向堆內存的指針。
再來仔細看一下 itab 結構體:_type 字段描述了實體的類型,包括內存對齊方式,大小等;inter 字段則描述了接口的類型。fun 字段放置和接口方法對應的具體數據類型的方法地址,實現接口調用方法的動態分派,一般在每次給接口賦值發生轉換時會更新此表,或者直接拿緩存的 itab。
這里只會列出實體類型和接口相關的方法,實體類型的其他方法并不會出現在這里。如果你學過 C++ 的話,這里可以類比虛函數的概念。
另外,你可能會覺得奇怪,為什么 fun 數組的大小為 1,要是接口定義了多個方法可怎么辦?實際上,這里存儲的是第一個方法的函數指針,如果有更多的方法,在它之后的內存空間里繼續存儲。從匯編角度來看,通過增加地址就能獲取到這些函數指針,沒什么影響。順便提一句,這些方法是按照函數名稱的字典序進行排列的。
再看一下
interfacetype
類型,它描述的是接口的類型:
type interfacetype struct { typ _type pkgpath name mhdr []imethod }
可以看到,它包裝了
_type
類型,_type
實際上是描述 Go 語言中各種數據類型的結構體。我們注意到,這里還包含一個mhdr
字段,表示接口所定義的函數列表,pkgpath
記錄定義了接口的包名。
這里通過一張圖來看下
iface
結構體的全貌:
接著來看一下
eface
的源碼:
type eface struct { _type *_type data unsafe.Pointer }
相比
iface
,eface
就比較簡單了。只維護了一個_type
字段,表示空接口所承載的具體的實體類型。data
描述了具體的值。
我們來看個例子:
package main import "fmt" func main() { x := 200 var any interface{} = x fmt.Println(any) g := Gopher{"Go"} var c coder = g fmt.Println(c) } type coder interface { code() debug() } type Gopher struct { language string } func (p Gopher) code() { fmt.Printf("I am coding %s language\n", p.language) } func (p Gopher) debug() { fmt.Printf("I am debuging %s language\n", p.language) }
執行命令,打印出匯編語言:
go tool compile -S ./src/main.go
可以看到,main 函數里調用了兩個函數:
func convT2E64(t *_type, elem unsafe.Pointer) (e eface) func convT2I(tab *itab, elem unsafe.Pointer) (i iface)
上面兩個函數的參數和
iface
及eface
結構體的字段是可以聯系起來的:兩個函數都是將參數組裝
一下,形成最終的接口。
作為補充,我們最后再來看下
_type
結構體:
type _type struct { // 類型大小 size uintptr ptrdata uintptr // 類型的 hash 值 hash uint32 // 類型的 flag,和反射相關 tflag tflag // 內存對齊相關 align uint8 fieldalign uint8 // 類型的編號,有bool, slice, struct 等等等等 kind uint8 alg *typeAlg // gc 相關 gcdata *byte str nameOff ptrToThis typeOff }
Go 語言各種數據類型都是在
_type
字段的基礎上,增加一些額外的字段來進行管理的:
type arraytype struct { typ _type elem *_type slice *_type len uintptr } type chantype struct { typ _type elem *_type dir uintptr } type slicetype struct { typ _type elem *_type } type structtype struct { typ _type pkgPath name fields []structfield }
這些數據類型的結構體定義,是反射實現的基礎。
原文鏈接:https://blog.csdn.net/qq_53267860/article/details/127101278
相關推薦
- 2022-10-28 Go語言開發保證并發安全實例詳解_Golang
- 2022-07-12 合理使用gateWay過濾器,實現Concroller自動注入用戶信息
- 2022-05-24 python使用torch隨機初始化參數_python
- 2022-10-20 Android開發使用RecyclerView添加點擊事件實例詳解_Android
- 2022-11-14 Python語言中Tuple的由來分析_python
- 2022-08-15 Python?time模塊之時間戳與結構化時間的使用_python
- 2022-08-11 C++通過boost.date_time進行時間運算_C 語言
- 2022-08-27 python?中defaultdict()對字典進行初始化的用法介紹_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支