解決golang 反射interface{}做零值判斷的一個(gè)重大坑
在對(duì)float零值判斷時(shí)往往只需要和0做==即可,所以曾經(jīng)int和float都用==0來(lái)做對(duì)比,
比如下方:
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{}對(duì)數(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,暫時(shí)的解決方案就是必須寫(xiě)成v==0.
//相對(duì)正確的寫(xiě)法
func f(arg interface{}){
switch v:=arg.(type) {
case float32,float64:
fmt.Println(v==0.)
case int,int32,in64:
fmt.Pringtln(v==0)
}
}
//錯(cuò)誤的寫(xiě)法
func f(arg interface{}){
switch v:=arg.(type) {
case float32,float64,int,int64,int32:
fmt.Println(v==0)
}
}
但是,這樣寫(xiě)還是會(huì)有bug,比如傳一個(gè)float的默認(rèn)值,這個(gè)場(chǎng)景經(jīng)過(guò)仔細(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)過(guò)仔細(xì)查找原因,原來(lái)float的相等判定的解決方案是固定的,因?yàn)橛?jì)算機(jī)內(nèi)部float不存在全等,所以任何兩個(gè)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)
}
}
這里還有最后一個(gè)坑會(huì)踩,那就是switch v:=arg.(type)里的v,在case路由中,如果不能精準(zhǔn)到單路線(xiàn),v還是一個(gè)interface{}
//編譯器不通過(guò)的寫(xiě)法,理由是,不支持interface{}類(lèi)型的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)
}
我擦類(lèi)~
補(bǔ)充:golang interface{}類(lèi)型轉(zhuǎn)換 bson.M 遇到莫名其妙的問(wèn)題
背景
從mongo數(shù)據(jù)庫(kù)中取出數(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返回?cái)?shù)據(jù)后 對(duì)interface數(shù)據(jù)進(jìn)行解析

問(wèn)題
問(wèn)題就是出現(xiàn)在解析的時(shí)候報(bào)了錯(cuò)

特地debug了一下queryresult的類(lèi)型 發(fā)現(xiàn)的確是bson.M 然后他就是報(bào)錯(cuò)
嘗試了各種方法,打了無(wú)數(shù)debug,并沒(méi)發(fā)現(xiàn)問(wèn)題。
解決
最后還是在同事幫助下。。去掉了這里的斷言看看問(wèn)題

看到了panic后的問(wèn)題顯示

第一眼看的一頭霧水。。 bson.M not bson.M
最后想到,這是在兩個(gè)文件下的代碼 然而


一個(gè)引用了服務(wù)本地的mgo包 另一個(gè)則使用了gopath內(nèi)的包所以判斷成了兩個(gè)不一樣的類(lèi)型 真的是尷尬0.0
教訓(xùn)總結(jié)
同一個(gè)服務(wù)用到的相同包一定要調(diào)同一個(gè)地方的?。?!
同一個(gè)服務(wù)用到的相同包一定要調(diào)同一個(gè)地方的?。?!
同一個(gè)服務(wù)用到的相同包一定要調(diào)同一個(gè)地方的?。?!
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
相關(guān)文章
Golang內(nèi)存泄漏場(chǎng)景以及解決方案詳析
golang中內(nèi)存泄露的發(fā)現(xiàn)與排查一直是來(lái)是go開(kāi)發(fā)者頭疼的一件事,下面這篇文章主要給大家介紹了關(guān)于Golang內(nèi)存泄漏場(chǎng)景以及解決的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01
深入了解Golang?interface{}的底層原理實(shí)現(xiàn)
在?Go?語(yǔ)言沒(méi)有泛型之前,接口可以作為一種替代實(shí)現(xiàn),也就是萬(wàn)物皆為的?interface。那到底?interface?是怎么設(shè)計(jì)的底層結(jié)構(gòu)呢?下面咱們透過(guò)底層分別看一下這兩種類(lèi)型的接口原理。感興趣的小伙伴們可以參考借鑒,希望對(duì)大家能有所幫助2022-10-10
深入了解Go語(yǔ)言的基本語(yǔ)法與常用函數(shù)
這篇文章主要為大家詳細(xì)介紹一下Go語(yǔ)言中的基本語(yǔ)法與常用函數(shù),文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)Go語(yǔ)言有一定的幫助,需要的可以參考一下2022-07-07
go語(yǔ)言編程之美自定義二進(jìn)制文件實(shí)用指南
這篇文章主要介紹了go語(yǔ)言編程之美自定義二進(jìn)制文件實(shí)用指南2023-12-12
利用Golang實(shí)現(xiàn)TCP連接的雙向拷貝詳解
公司中遇到了一個(gè)使用golang編寫(xiě)的agent程序,所以這篇文章主要給大家介紹了關(guān)于利用Go如何實(shí)現(xiàn)TCP連接的雙向拷貝的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考,下面隨著小編來(lái)一起看看吧。2017-09-09
Go語(yǔ)言實(shí)現(xiàn)一個(gè)Http Server框架(二) Server的抽象
上一篇文章對(duì)http庫(kù)的基本使用做了說(shuō)明,這篇文章主要介紹了如何實(shí)現(xiàn)一個(gè)簡(jiǎn)單地httpServer,文中代碼示例非常詳細(xì),感興趣的朋友可以參考下2023-04-04
如何使用golang實(shí)現(xiàn)traceroute
這篇文章主要介紹了如何使用golang實(shí)現(xiàn)traceroute,該工具在linux環(huán)境下的命令是traceroute或者tracepath,在windows下命令是tracert,本文給大家詳細(xì)講解需要的朋友可以參考下2023-04-04

