Go interface 判空问题

1,335 阅读1分钟

背景案例

日常开发中经常会遇到返回interface,而这里就会面临判空的问题。

func main() {
   var x interface{}
   IsNil("x", x)
   
   var y *string = nil
   IsNil("y", y)

   var z = (interface{})(y)
   IsNil("z", z)
}

func IsNil(paramName string, input interface{}) {
   if input == nil {
      fmt.Printf(" %s == nil \n", paramName)
      return
   }
   fmt.Printf(" %s != nil \n", paramName)
}

输出结果

image.png

这里为什么转成interface{}后,变成!=nil了呢

interface 底层结构

go 中 interface底层实现分为两类,eface为 empty-face,指不包含方法的interface结构,而iface则反之包含方法

type iface struct {
   tab  *itab
   data unsafe.Pointer
}

type eface struct {
   _type *_type
   data  unsafe.Pointer
}

但不是管是eface还是iface,其中都有一个_type属性 和 data

type itab struct {
   inter *interfacetype
   _type *_type
   hash  uint32 // copy of _type.hash. Used for type switches.
   _     [4]byte
   fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}

nil的定义

// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type

对于interface而言,nil的含义为data为空且类型为空。这就很好解释了为什么interface判空不能直接通过==来判断。

func main() {
   var x interface{}
   fmt.Println(reflect.TypeOf(x))
   IsNil("x", x)

   var y *string = nil
   fmt.Println(reflect.TypeOf(y))
   IsNil("y", y)

   var z = (interface{})(y)
   fmt.Println(reflect.TypeOf(z))
   IsNil("z", z)

}

输出结果 image.png

如何判断nil

func IsNil(input interface{}) bool {
   if input == nil {
      return true
   }
   if reflect.TypeOf(input).Kind() == reflect.Ptr && reflect.ValueOf(input).IsNil() {
      return true
   }
   return false
}