判断一下以下代码会打印什么?
package main
import (
"fmt"
)
type MyError struct{}
func (e *MyError ) Error() string {
return "a"
}
func main() {
var a *MyError
if a == nil {
fmt.Println("a == nil")
} else {
fmt.Println("a != nil")
}
fmt.Println("a Error():", a.Error())
var b error = a
if b == nil {
fmt.Println("b == nil")
} else {
fmt.Println("b != nil")
}
fmt.Println("b Error():", b.Error())
}
.
.
.
.
.
.
.
.
.
.
.
.
会打印出
a == nil
a Error(): a
b != nil
b Error(): a
和你预期是否一致呢? 试着理解一下这个问题.
---- 分割线 ----
在底层,interface作为两个成员实现:一个类型和一个值。该值被称为接口的动态值, 它是一个任意的具体值,而该接口的类型则为该值的类型。对于 int 值3, 一个接口值示意性地包含(int, 3)。
只有在内部值和类型都未设置时(nil, nil),一个接口的值才为 nil。
在以上代码中b存储的是(*MyError, nil), 因此,b是非 nil 的,即使在该指针的内部值为 nil。
实践
此问题并不出现在面试题中, 在日常封装接口(大多是自定义error才会用==nil的判断)时, 就要注意此问题, 如下面两种写法:
type MyError struct{}
func (e *MyError ) Error() string {
return "a"
}
// good
func NewError(msg string) error{
if (msg==""){
return nil
}
return &MyError{}
}
// bad
func NewError(msg string) *MyError{
if (msg==""){
return nil
}
return &MyError{}
}
其中bad写法就会导致err == nil 为false
var err error
err = NewError("")
print(err == nil) // false
网友评论