golang 这段代码为什么会触发 panic ?

golang 这段代码 checkError 为什么会触发 panic ?

package main

import (
    "fmt"
)

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(err error) {
    if err != nil {
        panic(err)
    }
}

func main() {
    var e *Error
    checkError(e)
}

checkError 传参 err 是 nil,为什么也会进入到 panic ?

阅读 4.6k
4 个回答

题主还是不明白nil,我用你的例子来给你介绍一下。
首先你在main函数里的

var e *Error

这里的e是一个Error类型的指针,而指针的自动初始化为nil,在这里e的确是nil没有错,e==nil

但是当你把e传入进checkError函数时,发生了变化,因为接受的形参是个error接口类型,所以形参err是一个接口值,而一个接口值实际上是包含了实际值和动态类型两个部分的。

err这个接口值大概是这样的(nil,*Error),这里后面的部分*Error表示它的动态类型。

你把err和外面的e做比较时,因为接口类型会断言,所以会相等,err==e

但是你把err和nil做比较时,nil实际上是(nil,nil)这种,比较结果自然是false err!=nil

你把nil用显示类型转换一下,变成了(nil,*Error)后就和err相同了, err==(*Error)(nil)

总而言之,就是你把一个拥有实际类型的指针传给了接口,那么这个接口值永远不可能是nil。

golang这个设计是因为接口值持有的类型必须是动态的。

只有当interface为零值,即<itable, data>=<nil, nil>时,才能等于nil.

var e *Error
d := (*struct {
        itab uintptr
        data uintptr
    })(unsafe.Pointer(&e))
//输出&{0 17864464}
//d.data 不为空所以e不为nil
fmt.Println(d)

可以加上这句,fmt.Println(e.errCode)
e没有初始化

因为e 没有初始化,所以抛出空指针错误。
new 一下就可以了
var e *Error = new (Error)

@pinecone @dliu
但是在 main 函数打印 e :

func main() {
    var e *Error
    fmt.Println("e:", e)
    checkError(e)
}

结果:

e: <nil>

那么 e 是 nil ,不应该进入 panic 啊

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题