这里重点通过 eface 和 dequeueNil 来阐明golang 中的 interface{} 是由 type 和 value 2个机器字组成。当 type 和 value 都为nil(即null ) 时, 才为 nil 的interface;当 type!=nil,value==nil 时,不是 nil 的interface.
package main import ( "fmt" "reflect" "sync/atomic" "unsafe" ) type eface struct { typ, val unsafe.Pointer } // dequeueNil is used in poolDeqeue to represent interface{}(nil). // Since we use nil to represent empty slots, we need a sentinel value // to represent nil. type dequeueNil *struct{} func main() { // dnil 作为 *struct{} 确实为nil 即 null 指针,1个机器字,但是 // 当它转为 interface{} 后,2个机器字,不是 nil 的 interface // dnil type: main.dequeueNil , value: <nil> dnil := dequeueNil(nil) fmt.Println("dnil type:", reflect.TypeOf(dnil), ", value:", reflect.ValueOf(dnil)) // dnil == nil 成立 if dnil == nil { fmt.Println("dnil == nil") } else { fmt.Println("dnil != nil") } var dnil2 interface{} = dnil fmt.Println("dnil2 type:", reflect.TypeOf(dnil2), ", value:", reflect.ValueOf(dnil2)) // dnil2 != nil 成立 if dnil2 != nil { fmt.Println("dnil2 != nil") } else { fmt.Println("dnil2 == nil") } // slot 是非空指针, 转成 interface{} 没有问题;但是 // 由于 eface{} 的两个指针 typ, val 都为空指针 // 因此等价于 interface{} 的 type vaule 都为 null,因 // 此转成 interface{} 后就是 nil 的 interface{} // 因此这里解开了神秘的 interface{} 的,interface{} 实 // 际上就是含有 type, value 指针的一个结构体。 // 当 interface{} 的 type 和value 同时为 null 指针时, // 代表 nil interface. var slot2 *eface = &eface{} nilInterface := *(*interface{})(unsafe.Pointer(slot2)) fmt.Println("unsafe.Pointer(slot)", unsafe.Pointer(slot2)) fmt.Println("nilInterface type:", reflect.TypeOf(nilInterface), ", value:", reflect.ValueOf(nilInterface)) // 相等 if nilInterface == nil { fmt.Println("nilInterface == nil") } else { fmt.Println("nilInterface != nil") } // 不相等, 因为 dequeueNil(nil) 转成 interface 后 type 不为 null 指针 if nilInterface == dequeueNil(nil) { fmt.Println("nilInterface == dequeueNil(nil)") } else { fmt.Println("nilInterface != dequeueNil(nil)") } // Initialize the chain. const initSize = 8 // Must be a power of 2 vals := make([]eface, initSize) // 现在我来尝试回答作者为什么要使用 dequeueNil(nil) 来作为 // interface{}(nil) 即 nil interface 的代表呢? 正如注释 // 所说的那样,因为我们使用 nil interface 代表 // slot 是空的 (用户没放任何东西,可以使用). 如果外部 push // 一个 nil interface 进来, 如果直接保存,那么会以为这个 // slot 是空的,仍然可以使用。但是如果此时保存的是 dequeueNil(nil), // dequeueNil(nil) 转成 interface 后是 type 不为null, value // 为null 的非 nil interface, 就可以区别开来了. pushHead(vals, 0, nil) if v2, ok2 := popHead(vals, 0); ok2 { fmt.Println("v2:", v2) } else { fmt.Println("not ok") } } func pushHead(vals []eface, head uint32, val interface{}) { slot := &vals[head&uint32(len(vals)-1)] // Check if the head slot has been released by popTail. typ := atomic.LoadPointer(&slot.typ) if typ != nil { // Another goroutine is still cleaning up the tail, so // the queue is actually still full. return } // 问题,如果把下面这段 if 代码注释, 然后执行 // pushHead(vals, 0, nil), popHead(vals, 0) // popHead 中的 val := *(*interface{})(unsafe.Pointer(slot)) // 会发生空指针非法访问吗? 答案是不会,因为 // *(*interface{})(unsafe.Pointer(slot)) = nil // 只是等价于 slot.typ = null, slot.val = null, // 也等价于 *slot = eface{} // The head slot is free, so we own it. if val == nil { val = dequeueNil(nil) } // 等价于 slot.typ = val.type, slot.val = val.value *(*interface{})(unsafe.Pointer(slot)) = val } func popHead(vals []eface, head uint32) (interface{}, bool) { var slot *eface slot = &vals[head&uint32(len(vals)-1)] val := *(*interface{})(unsafe.Pointer(slot)) if val == dequeueNil(nil) { val = nil } // Zero the slot. Unlike popTail, this isn't racing with // pushHead, so we don't need to be careful here. *slot = eface{} return val, true }
欢迎关注我的微信公众号[数学345]:长按"识别图中二维码";或打开微信扫一扫。