如有任何問題或建議,歡迎及時交流和碰撞。個人公衆號是 【腦子進煎魚了】,GitHub 地址: https://github.com/eddycjy。
你們好,我是煎魚。git
前幾天在讀者交流羣裏看到一位小夥伴,針對 interface 的使用有了比較大的疑惑。github
無獨有偶,我也在網上看到有小夥伴在 Go 面試的時候被問到了:golang
今天特地分享出來讓你們避開這個坑。面試
第一個例子,以下代碼:數據結構
func main() { var v interface{} v = (*int)(nil) fmt.Println(v == nil) }
你以爲輸出結果是什麼呢?架構
答案是:微服務
false
爲何不是 true
。明明都已經強行置爲 nil
了。是否是 Go 編譯器有問題?spa
第二個例子,以下代碼:設計
func main() { var data *byte var in interface{} fmt.Println(data, data == nil) fmt.Println(in, in == nil) in = data fmt.Println(in, in == nil) }
你以爲輸出結果是什麼呢?指針
答案是:
<nil> true <nil> true <nil> false
這可就更奇怪了,爲何剛剛聲明出來的 data
和 in
變量,確實是輸出結果是 nil
,判斷結果也是 true
。
怎麼把變量 data
一賦予給變量 in
,世界就變了?輸出結果依然是 nil
,但斷定卻變成了 false
。
和上面的第一個例子結果相似,真是神奇。
interface 判斷與想象中不同的根本緣由是,interface 並非一個指針類型,雖然他看起來很像,以致於誤導了很多人。
咱們鑽下去 interface,interface 共有兩類數據結構:
runtime.eface
結構體:表示不包含任何方法的空接口,也稱爲 empty interface。runtime.iface
結構體:表示包含方法的接口。看看這二者相應的底層數據結構:
type eface struct { _type *_type data unsafe.Pointer } type iface struct { tab *itab data unsafe.Pointer }
你會發現 interface 不是單純的值,而是分爲類型和值。
因此傳統認知的此 nil 並不是彼 nil,必須得類型和值同時都爲 nil 的狀況下,interface 的 nil 判斷纔會爲 true。
與其說是解決方法,不如說是委婉的破局之道。在不改變類型的狀況下,方法之一是利用反射(reflect),以下代碼:
func main() { var data *byte var in interface{} in = data fmt.Println(IsNil(in)) } func IsNil(i interface{}) bool { vi := reflect.ValueOf(i) if vi.Kind() == reflect.Ptr { return vi.IsNil() } return false }
利用反射來作 nil 的值判斷,在反射中會有針對 interface 類型的特殊處理,最終輸出結果是:true,達到效果。
其餘方法的話,就是改變原有的程序邏輯,例如:
Go interface 是 Go 語言中最經常使用的類型之一,你們用慣了 if err != nil
就很容易順手就踩進去了。
建議你們要多留個心眼,若是對 interface 想要有更進一步的瞭解,能夠看看個人這篇深刻解析的文章:《一文吃透 Go 語言解密之接口 interface》。
小夥伴們有沒有踩到過,或遇到過 interface 相關的 「坑」 呢?歡迎你們下方留言討論,分享出來。
你們一塊兒衝!
分享 Go 語言、微服務架構和奇怪的系統設計,歡迎你們關注個人公衆號和我進行交流和溝通。
最好的關係是互相成就,各位的點贊就是煎魚創做的最大動力,感謝支持。