interface 底层结构
#
interface{} 底层存储结构如下所示:
// ----------- runtime/runtime2.go -----------------
type iface struct {
tab *itab
data unsafe.Pointer
}
type eface struct {
_type *_type
data unsafe.Pointer
}
type itab = abi.ITab
type _type = abi.Type
// ----------- internal/abi/iface.go -----------------
// The first word of every non-empty interface type contains an *ITab.
// It records the underlying concrete type (Type), the interface type it
// is implementing (Inter), and some ancillary information.
//
// allocated in non-garbage-collected memory
type ITab struct {
Inter *InterfaceType
Type *Type
Hash uint32 // copy of Type.Hash. Used for type switches.
Fun [1]uintptr // variable sized. fun[0]==0 means Type does not implement Inter.
}
可以看到 interface{} 底层被存储为两种类型:
iface表示有方法集的接口类型变量eface表示没有方法的空接口类型变量,也就是interface{}类型的变量
interface 注意要点
#
判断 interface{} 是否等于 nil #
比如以下函数 returnError 返回 error, 处理返回的 error 时要判断是不是 nil
type MyError string
func (e *MyError) Error() string { return string(*e) }
func bad() bool { return false }
func returnError() error {
var err *MyError = nil
if bad() {
badErr := MyError("bad error")
err = &badErr
}
return err
}
既然是注意点,那就肯定不是简单的 v == nil 的方式比较。
首先简化一下上述函数,因为一直不会进入
if bad() {}, 所以简化为
func returnError() error {
var err *MyError = nil
return err
}
这里也要注意,上述代码和和**直接
var err *MyError = nil然后比较err是否为nil是不一样的。**这种err是*MyError类型,可以直接与nil比较并且相等,不是interface{}
而 func returnError() error 相当与如下代码,返回的是 interface{}:
var ret error
var err *MyError = nil
ret = err
return ret
上述代码中, 相当于把一个类型为
*MyError但是值为nil的变量赋值给了interface{}类型的ret,因为ret有实现error接口的方法func Error() string,所以底层使用iface存储,其中:
iface.tab.Type会存储*MyError类型iface.data为 nil当
ret直接与nil比较时会先比较类型,*MyError和nil不相等,如果直接比较就容易被坑!!!
所以:
当调用一些奇怪函数返回 interface{} 类型变量或者函数接收 interface{} 类型变量并且需要判断是否为 nil 时就要张个心眼。可以使用如下函数判断一个 interface{} 是否为 nil:
func IsNil(v interface{}) bool {
if v == nil {
return true
}
switch reflect.TypeOf(v).Kind() {
case reflect.Chan, reflect.Func, reflect.Slice,
reflect.Map, reflect.Ptr:
return reflect.ValueOf(v).IsNil()
default:
return false
}
}