golang 反射interface零值判断 解决golang 反射interface{}做零值判断的一个重大坑

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

golang 反射interface零值判断 解决golang 反射interface{}做零值判断的一个重大坑

fwhezfwhez   2021-04-25 我要评论
想了解解决golang 反射interface{}做零值判断的一个重大坑的相关内容吗,fwhezfwhez在本文为您仔细讲解golang 反射interface零值判断的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:golang,反射interface{},零值判断,下面大家一起来学习吧。

在对float零值判断时往往只需要和0做==即可,所以曾经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)
    }

结果:

float 0==0: true

float -> interface{} -> float true

float -> interface -.type-> float true

但是,golang里interface{}对数据的装箱 相比于 函数里 [入参 interface{}] 的装箱是迥然不同的 ,比如:

func f(arg interface{}){
    switch v:=arg.(type) {
    case float32,float64:
        fmt.Println(v==0)
    }
}
func main(){
    f(0.)
}

结果:

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的默认值,这个场景经过仔细推敲,重现在这里:

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)
}

结果:

false

我擦咧,咋回事,还是false

最后经过仔细查找原因,原来float的相等判定的解决方案是固定的,因为计算机内部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路由中,如果不能精准到单路线,v还是一个interface{}

//编译器不通过的写法,理由是,不支持interface{}类型的v,进行float64(v)操作
func f(arg interface{}){
    switch v:=arg.(type) {
    case float32,float64:
        r:=float64(v)
        fmt.Println(math.Abs(r-0)<0.0000001)
}

我擦类~

补充:golang interface{}类型转换 bson.M 遇到莫名其妙的问题

背景

从mongo数据库中取出数据以interface{}格式返回,解析返回的数据。

1.从mongo中取数据

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返回数据后 对interface数据进行解析

问题

问题就是出现在解析的时候报了错

特地debug了一下queryresult的类型 发现的确是bson.M 然后他就是报错

尝试了各种方法,打了无数debug,并没发现问题。

解决

最后还是在同事帮助下。。去掉了这里的断言看看问题

看到了panic后的问题显示

第一眼看的一头雾水。。 bson.M not bson.M

最后想到,这是在两个文件下的代码 然而

一个引用了服务本地的mgo包 另一个则使用了gopath内的包所以判断成了两个不一样的类型 真的是尴尬0.0

教训总结

同一个服务用到的相同包一定要调同一个地方的!!!

同一个服务用到的相同包一定要调同一个地方的!!!

同一个服务用到的相同包一定要调同一个地方的!!!

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。如有错误或未考虑完全的地方,望不吝赐教。

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们