美文网首页
为什么nil error不等于nil

为什么nil error不等于nil

作者: 绝望的祖父 | 来源:发表于2018-01-06 13:58 被阅读104次

    先看一段代码

    package main
    
    type Error struct {
        errCode uint8
    }
    
    func (e *Error) Error() string {
        switch e.errCode {
        case 1:
            return "file not found"
        case 2:
            return "time out"
        case 3:
            return "permission denied"
        default:
            return "unknown error"
        }
    }
    
    func checkError(e error) {
        if e != nil {
            panic(e)
        }
    }
    
    func main() {
        var e *Error
        checkError(e)
    }
    

    此时e是nil的,但是当checkError时却会panic,为什么?

    在底层,接口被实现为两个元素,一个类型和一个值。该值被称为接口的动态值, 它是一个任意的具体值。而该接口的类型就是该值的类型。对于int值3,接口值示意性地包含(int,3)。

    只有在接口内部的值和类型同时为nil时,一个接口的值才为nil,特别是,一个nil接口将总是包含一个nil类型。如果我们在一个interface中存储了一个int类型的空指针,那么无论这个int指针的值是什么,接口的内部类型值都将为*int。因此,这样的接口值将会是非nil的,即使该内部指针是一个nil指针。

    这种情况可能会引起混淆,在一个接口值(如error返回值)中存储一个nil时会出现这种情况:

    func returnsError() error {
        var p *MyError = nil
        if bad() {
            p = ErrBad
        }
        return p // Will always return a non-nil error.
    }
    

    如果一切顺利,函数返回一个nil p,所以返回值是一个error的接口值(* MyError,nil)。这意味着,如果调用者将返回的error与nil做相等比较,即使没有发生任何错误,对比的结果也会是false。为了给调用者返回一个适当的nil error,函数必须返回一个明确的nil:

    func returnsError() error {
        if bad() {
            return ErrBad
        }
        return nil
    }
    

    对于返回error的函数来说,总是在签名中使用error类型(如上所述)而不是像MyError这样的具体类型,这是个好习惯,以帮助保证正确创建error。作为一个例子,os.Open返回一个错误,即使不是nil,它总是具体的类型 *os.PathError。

    无论何时使用接口,都会出现类似于这里描述的情况。请记住,如果接口中存储了具体的值,接口将不会为nil。欲了解更多信息,请参阅反射法则

    参考文献:Why is my nil error value not equal to nil?

    相关文章

      网友评论

          本文标题:为什么nil error不等于nil

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