MENU

[FAQ]为什么我的nil错误值不等于nil?

November 7, 2020 • Go FAQ

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

只有在内部值和类型都未设置时(nil, nil),一个接口的值才为 nil。特别是,一个 nil 接口将总是拥有一个 nil 类型。若我们在一个接口值中存储一个 *int 类型的指针,则内部类型将为 *int,无论该指针的值是什么:(*int, nil)。 因此,这样的接口值会是非 nil 的,_即使在该指针的内部为_ nil

这种情况会让人迷惑,而且当 nil 值存储在接口值内部时这种情况总是发生, 例如错误返回:

func returnsError() error {
    var p *MyError = nil
    if bad() {
        p = ErrBad
    }
    return p // 将总是返回一个非nil错误。
}

如果一切顺利,该函数会返回一个 nilp, 因此该返回值为拥有(*MyError, nil)的 error 接口值。这也就意味着如果调用者将返回的错误与 nil 相比较, 它将总是看上去有错误,即便没有什么坏事发生。要向调用者返回一个适当的 nilerror,该函数必须返回一个显式的 nil

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

这对于总是在签名中使用 error 类型返回错误(正如我们上面做的)而非像 *MyError 这样具体类型的函数来说是个不错的主意,它可以帮助确保错误被正确地创建。 例如,即使 os.Open 返回一个 error, 若非 nil 的话,它总是具体的类型 *os.PathError

对于那些描述,无论接口是否被使用,相似的情形都会出现。只要记住,如果任何具体的值已被存储在接口中, 该接口就不为 nil。更多信息请访问反射法则

ArchivesQR Code
QR Code for this page
Tipping QR Code