當將一個值為nil的接口變量w賦值給空接口類型i后胧谈,i為nil。
// case 1
var i interface{}
var w io.Writer
i = w
print(i == nil) // true
但是將一個值為nil的接口指針變量w賦值給空接口類型i后荸频,i就不等于nil了菱肖。
// case 2
var i interface{}
var w *io.Writer
i = w
print(i == nil) // false
what???
當我無意間測試到這種case之后,缺失有點不知所以旭从。
下面我們就通過反射和debug查看到底發(fā)生了什么稳强。
有個常識需要再提一下:判斷一個空接口類型的變量是否為nil時,只有當type和value同時為nil時和悦,空接口類型變量才為nil退疫。
有個進階的知識需要提前說一下:空接口類型數(shù)據(jù)在類型系統(tǒng)中的表示對應的是runtime.eface,如下所示鸽素;在反射包中有對應結構褒繁,那就是:reflect.emptyInterface,結構如下:
type eface struct {
_type *_type // 類型信息
data unsafe.Pointer // 值信息
}
// emptyInterface is the header for an interface{} value.
type emptyInterface struct {
typ *rtype // 類型信息
word unsafe.Pointer // 值信息
}
先用goland debug一下(使用reflect.TypeOf方法測試i的類型信息)付鹿。
case 1的情況:
image.png
case 2的情況:
image.png
可以看到case1的type為nil澜汤,而case2的type不為nil,所以case 2的i不為nil舵匾。
下面通過調試工具delve來看一下結果:
case 1:
image.png
case 2:
image.png
和顯然和goland中調試結果是一致的俊抵。只不過我們在使用delve調試的時候,可以輸出空接口runtime的表示坐梯,而goland ide只能通過調用反射功能窺視類型數(shù)據(jù)徽诲。
另外,我們注意到case 2中kind=54吵血,和我們見到的reflect.Kind枚舉數(shù)據(jù)對不上谎替。則是因為kind: 54需要和kindMask = (1 << 5) - 1,做一次與運算就和reflect.Kind對應了蹋辅,與運算后是22钱贯,就是reflect.Ptr的值。
func (t *rtype) Kind() Kind { return Kind(t.kind & kindMask) }
// A Kind represents the specific kind of type that a Type represents.
// The zero Kind is not a valid kind.
type Kind uint
const (
Invalid Kind = iota
Bool
Int
Int8
Int16
Int32
Int64
Uint
Uint8
Uint16
Uint32
Uint64
Uintptr
Float32
Float64
Complex64
Complex128
Array
Chan
Func
Interface
Map
Ptr
Slice
String
Struct
UnsafePointer
)