美文网首页
golang err!=nil

golang err!=nil

作者: 小白小白啦 | 来源:发表于2022-09-15 13:01 被阅读0次

    今天写代码的时候,发现一个和预期不符合的逻辑。简单描述就是把一个值为nil的A类型的error赋值给接口error,和nil比较竟然是false。在此记录一下。

    复现

    代码如下,自定义一个error类型。然后预计代码输出是<nil> false,但是实际输出是<nil> true。非常非常奇怪,nil竟然不等于nil

    package main
    
    import "fmt"
    
    type Err struct {
        err string
    }
    
    func (e *Err) Error() string {
        return e.err
    }
    func returnErr() *Err {
        return nil
    }
    func main() {
        var err error
        err = returnErr()
        fmt.Println(err, err != nil)
    }
    

    解决办法
    不要将该结果赋给一个接口变量。如,将 err = returnErr() 改成 err1 := returnErr()

    func main() {
        err := returnErr()
        fmt.Println(err, err != nil)
    }
    

    或者和原类型比较

    func main() {
        var err error
        err = returnErr()
        var e *Err
        fmt.Println(err, err != e)
    }
    

    原因

    接口 interface 造成的。具体可以查看 官网 FAQ

    简单说,interface 被两个元素 value 和 type 所表示。只有在 value 和 type 同时为 nil 的时候,判断 interface == nil 才会为 true。而 err = returnErr() 这个过程中,虽然 value 为 nil,但 type 却为 *Err。

    下面的内容从《Go语言精进之路:从新手到高手编程思想、方法和技巧1》拷贝

    接口类型“动静兼备”的特性决定了它的变量的内部表示绝不像静态类型(如int、float64)变量那样简单。我们可以在$GOROOT/src/runtime/runtime2.go中找到接口类型变量在运行时的表示:

    image.png
    我们看到在运行时层面,接口类型变量有两种内部表示——eface和iface,这两种表示分别用于不同接口类型的变量。eface:用于表示没有方法的空接口(empty interface)类型变量,即interface{}类型的变量iface:用于表示其余拥有方法的接口(interface)类型变量。这两种结构的共同点是都有两个指针字段,并且第二个指针字段的功用相同,都指向当前赋值给该接口类型变量的动态类型变量的值。
    image.png
    而iface除了要存储动态类型信息之外,还要存储接口本身的信息(接口的类型信息、方法列表信息等)以及动态类型所实现的方法的信息,因此iface的第一个字段指向一个itab类型结构:
    image.png
    上面itab结构中的第一个字段inter指向的interfacetype结构存储着该接口类型自身的信息。interfacetype类型定义如下,该interfacetype结构由类型信息(typ)、包路径名(pkgpath)和接口方法集合切片(mhdr)组成。
    itab结构中的字段_type则存储着该接口类型变量的动态类型的信息,字段fun则是动态类型已实现的接口方法的调用地址数组。

    参考

    Golang 博主走过的有关 error 的一些坑

    相关文章

      网友评论

          本文标题:golang err!=nil

          本文链接:https://www.haomeiwen.com/subject/drmrortx.html