理解interface和nil

判断一下以下代码会打印什么?

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

参考

  • https://golang.org/doc/faq#nil_error

你可能感兴趣的:(理解interface和nil)