在go中一个比较大的陷阱就是 nil != nil 这个问题了,那么这个问题到底怎么来的?
看如下的示例代码
```
package main
import (
"reflect"
"log"
)
func see(i interface{}) {
t := reflect.TypeOf(i)
log.Println("类型是:", t)
v := reflect.ValueOf(i)
log.Println("值是:", v)
if i == nil {
log.Println("判断是否Nil:", i == nil)
return
}
log.Println("判断是否Nil:", i == nil)
if t.Kind() == reflect.Ptr {
log.Println("判断值是否Nil:", reflect.ValueOf(i).IsNil())
} else {
log.Println("判断值是否Nil: 非引用类型")
}
log.Println("===========================")
}
type C struct {
}
func main() {
// 传递的是值
see(C{})
// 传递的是引用
see(&C{})
c := &C{}
c = nil
// 传递的是引用,引用的值为Nil
see(c)
see(&c)
//传递一个nil
see(nil)
}
```
```
执行的结果
2018/05/29 10:44:18 类型是: main.C
2018/05/29 10:44:18 值是: {}
2018/05/29 10:44:18 判断是否Nil: false
2018/05/29 10:44:18 判断值是否Nil: 非引用类型
2018/05/29 10:44:18 ===========================
2018/05/29 10:44:18 类型是: *main.C
2018/05/29 10:44:18 值是: &{}
2018/05/29 10:44:18 判断是否Nil: false
2018/05/29 10:44:18 判断值是否Nil: false
2018/05/29 10:44:18 ===========================
2018/05/29 10:44:18 类型是: *main.C
2018/05/29 10:44:18 值是: <nil>
2018/05/29 10:44:18 判断是否Nil: false
2018/05/29 10:44:18 判断值是否Nil: true
2018/05/29 10:44:18 ===========================
2018/05/29 10:44:18 类型是: **main.C
2018/05/29 10:44:18 值是: 0xc042004030
2018/05/29 10:44:18 判断是否Nil: false
2018/05/29 10:44:18 判断值是否Nil: false
2018/05/29 10:44:18 ===========================
2018/05/29 10:44:18 类型是: <nil>
2018/05/29 10:44:18 值是: <invalid reflect.Value>
2018/05/29 10:44:18 判断是否Nil: true
```
这个问题反复就有人谈过了,就是 v != nil
有且仅在 v 的type 和 value 同时都是 nil的时候才成立
因此在把一个&Type 类型的值传递给一个签名为 i interface{} 的函数接收时,一定要小心判断接收到的值的问题
产生这种问题的原因interface{} 接收到的不是一个完全的裸指针,而是将传递的v 的类型签名和,值同时接收,因此出现了上面的问题,因为已经在函数内部声明过 v 的类型是 *C,因此即使 v = nil 后,函数see 在传递的时候依然自作聪明的将 其类型标记为*C,导致了see函数内 i != nil 判断的问题。
#1
更多评论
如果在 see(c) 前进行一次 c == nil 判断,你会发现的确返回的是true;
```
log.Println(c == nil)
see(c)
```
#2