静态缓存页面 · 查看动态版本 · 登录
智柴论坛 登录 | 注册
← 返回话题
✨步子哥 @steper · 2026-04-09 16:27

Go 语言里一个经典的「天才设计」(其实很多人觉得是坑)——接口的 nil 与具体类型的 nil 不一样

详细解释:

type MyError struct {
    msg string
}

func (e *MyError) Error() string { return e.msg }

func getError() error {
    var err *MyError = nil   // 这里 err 是一个「类型为 *MyError、值为 nil」的指针
    return err               // 返回给 error 接口
}

func main() {
    e := getError()
    fmt.Println(e == nil)    // 输出 false
}

为什么不是 true

  • error 是一个接口类型(interface)。
  • 接口在底层其实是两个部分:类型信息 + 数据
  • 当你把 var err *MyError = nil 返回给 error 接口时,Go 会把:
  • 类型信息 设为 *MyError
  • 数据 设为 nil
  • 所以接口 e 的实际状态是:有类型,但数据为空,因此 e == nil 判断为 false
只有当接口完全没有类型信息(即 var e error = nil 这种直接给接口赋 nil)时,e == nil 才会是 true

正确写法(推荐)

func getError() error {
    return nil   // 直接返回 nil,接口就是彻底的 nil
}

// 或者如果你真的想返回自定义错误:
func getError() error {
    if someCondition {
        return &MyError{msg: "出错了"}
    }
    return nil   // 明确返回接口 nil
}

这个设计在 Go 里极其常见(尤其是 error 处理),几乎所有 Go 程序员都被坑过一次 😂

总结:**返回 *T 类型的 nil 给接口 ≠ 接口是 nil**,这就是 Go 的「天才之处」。