Golang 中有一个表面上看起来很奇怪的的问题,如下的代码中的函数会始终返回一个不等于 nil 的 error.
func returnsError() error {
var p *MyError = nil
if bad() {
p = ErrBad
}
return p // Will always return a non-nil error.
}
func main() {
if err = returnsError(); err != nil {
// Will always print
fmt.Println("ERROR")
}
}要解释这个问题的原因,我们需要了解 Golang 中 interface 的内部实现。对于 interface 的实例 Golang 内部分为两个实现,iface 与 eface, 对应的代码在 runtime/runtime2.go 中。
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}eface用于表示没有方法的空接口( empty interface )类型变量,即interface{}类型的变量。iface用于表示其余拥有方法的接口类型变量。
我们可以理解为 interface 的内部实现中包含两个字段 (T, V) ,只有当 T 和 V 同时为 nil 时 (T=nil, v=nil) ,才能被判断为与 nil 相等。
在上面的例子中 var p *MyError = nil 相当于 var p *MyError = &MyError(nil) ,p 被初始化为了 (T=*MyError, V=nil) 的内部表示,所以始终不等于 nil 。所以对于声明为 AnyNonEmptyInterfaceType 的变量来说,始终会被初始化为非 nil 。而对声明为 interface{} 的变量来说,p interface{} = nil 的情况下,可以被判断为 nil。
所以 Golang 建议在所有有返回 error 的函数声明中都使用 error 类型来作 为函数的签名,如下:
func returnError() error {} // good
func returnError1() *MyError {} // badGolang 官方 FAQ 中对于该问题的解释 Golang FAQ 。