解決golang 反射interface{}做零值判斷的一個重大坑
在對float零值判斷時往往只需要和0做==即可,所以曾經(jīng)int和float都用==0來做對比,
比如下方:
in := 0. var tmp interface{} = float32(in) fmt.Println("float 0==0:", in == 0) fmt.Println("float -> interface{} -> float", tmp.(float32) == 0) switch v := tmp.(type) { case float32: fmt.Println("float -> interface -.type-> float", v == 0) }
結(jié)果:
float 0==0: true
float -> interface{} -> float true
float -> interface -.type-> float true
但是,golang里interface{}對數(shù)據(jù)的裝箱 相比于 函數(shù)里 [入?yún)?interface{}] 的裝箱是迥然不同的 ,比如:
func f(arg interface{}){ switch v:=arg.(type) { case float32,float64: fmt.Println(v==0) } } func main(){ f(0.) }
結(jié)果:
false
我擦咧,竟然是false,暫時的解決方案就是必須寫成v==0.
//相對正確的寫法 func f(arg interface{}){ switch v:=arg.(type) { case float32,float64: fmt.Println(v==0.) case int,int32,in64: fmt.Pringtln(v==0) } } //錯誤的寫法 func f(arg interface{}){ switch v:=arg.(type) { case float32,float64,int,int64,int32: fmt.Println(v==0) } }
但是,這樣寫還是會有bug,比如傳一個float的默認(rèn)值,這個場景經(jīng)過仔細(xì)推敲,重現(xiàn)在這里:
func f(arg interface{}){ switch v:=arg.(type) { case float32,float64: fmt.Println(v==0.) case int,int32,in64: fmt.Pringtln(v==0) } } func main(){ var i float32 f(i) }
結(jié)果:
false
我擦咧,咋回事,還是false
最后經(jīng)過仔細(xì)查找原因,原來float的相等判定的解決方案是固定的,因為計算機(jī)內(nèi)部float不存在全等,所以任何兩個float判定相等方法一定是|a-b|<0.0000001,最終:
func f(arg interface{}){ switch v:=arg.(type) { case float32: r:=float64(v) fmt.Println(math.Abs(r-0)<0.0000001) case float64: fmt.Println(math.Abs(v-0)<0.0000001) } }
這里還有最后一個坑會踩,那就是switch v:=arg.(type)里的v,在case路由中,如果不能精準(zhǔn)到單路線,v還是一個interface{}
//編譯器不通過的寫法,理由是,不支持interface{}類型的v,進(jìn)行float64(v)操作 func f(arg interface{}){ switch v:=arg.(type) { case float32,float64: r:=float64(v) fmt.Println(math.Abs(r-0)<0.0000001) }
我擦類~
補(bǔ)充:golang interface{}類型轉(zhuǎn)換 bson.M 遇到莫名其妙的問題
背景
從mongo數(shù)據(jù)庫中取出數(shù)據(jù)以interface{}格式返回,解析返回的數(shù)據(jù)。
1.從mongo中取數(shù)據(jù)
newSession := m.Session.Copy() defer newSession.Close() c := newSession.DB(database).C(collName) if err := c.Find(bson.M{"time": occurtime}).One(&data); err != nil { Error(err) }
2.mongo返回數(shù)據(jù)后 對interface數(shù)據(jù)進(jìn)行解析
問題
問題就是出現(xiàn)在解析的時候報了錯
特地debug了一下queryresult的類型 發(fā)現(xiàn)的確是bson.M 然后他就是報錯
嘗試了各種方法,打了無數(shù)debug,并沒發(fā)現(xiàn)問題。
解決
最后還是在同事幫助下。。去掉了這里的斷言看看問題
看到了panic后的問題顯示
第一眼看的一頭霧水。。 bson.M not bson.M
最后想到,這是在兩個文件下的代碼 然而
一個引用了服務(wù)本地的mgo包 另一個則使用了gopath內(nèi)的包所以判斷成了兩個不一樣的類型 真的是尷尬0.0
教訓(xùn)總結(jié)
同一個服務(wù)用到的相同包一定要調(diào)同一個地方的?。?!
同一個服務(wù)用到的相同包一定要調(diào)同一個地方的?。?!
同一個服務(wù)用到的相同包一定要調(diào)同一個地方的!?。?/p>
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。如有錯誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
深入了解Golang?interface{}的底層原理實現(xiàn)
在?Go?語言沒有泛型之前,接口可以作為一種替代實現(xiàn),也就是萬物皆為的?interface。那到底?interface?是怎么設(shè)計的底層結(jié)構(gòu)呢?下面咱們透過底層分別看一下這兩種類型的接口原理。感興趣的小伙伴們可以參考借鑒,希望對大家能有所幫助2022-10-10Go語言實現(xiàn)一個Http Server框架(二) Server的抽象
上一篇文章對http庫的基本使用做了說明,這篇文章主要介紹了如何實現(xiàn)一個簡單地httpServer,文中代碼示例非常詳細(xì),感興趣的朋友可以參考下2023-04-04