看看下面的代码。
Go 是隐式实现 interface 的,所以 TestStruct 是 EmptyInterface。
由于 *TestStruct 有一个 Func 函数,所以它还是 WithFuncInterface。
type EmptyInterface interface {
}
type WithFuncInterface interface {
Func()
}
type TestStruct struct {
Member int
}
func (t *TestStruct) Func() {
fmt.Printf("Haha\n")
}
好了,看下面的几个函数:判断参数是不是 nil。
func TestEmptyInterface(i EmptyInterface) {
fmt.Printf("Interface: %v\n", i == nil)
}
func TestWithFuncInterface(i WithFuncInterface) {
fmt.Printf("Func Interface: %v\n", i == nil)
}
func TestWithFuncStruct(i *TestStruct) {
fmt.Printf("Struce Interface: %v\n", i == nil)
}
接下来看看 main 函数。
func main() {
var test *TestStruct = nil
TestEmptyInterface(test)
TestWithFuncInterface(test)
TestWithFuncStruct(test)
test.Func()
}
你一定觉得我在逗你,这显然会 print 3 个 true 并且产生一个 NullPointer 之类的错。
然而事实是:
Haha!
这段代码无情地嘲笑着你。
全是 true 的情形:
func main() {
var test *TestStruct = nil
TestEmptyInterface(test)
TestWithFuncInterface(test)
TestWithFuncStruct(test)
test.Func()
//fmt.Printf("%v", test.Member) <- NullPointer!
TestEmptyInterface(nil) // <- True
TestWithFuncInterface(nil) // <- True
TestWithFuncStruct(nil) // <- True
}
当然,你可以用反射:
func TestEmptyInterface(i EmptyInterface) {
fmt.Printf("Interface: %v\n", i == nil)
fmt.Printf("Interface Reflect: %v\n", reflect.ValueOf(i) == i)
fmt.Printf("Interface Reflect: %v\n", reflect.ValueOf(i))
fmt.Printf("Interface Reflect: %v\n", reflect.ValueOf(i).IsNil())
}
输出是:
然而,你不能:
fmt.Printf("Interface Reflect: %v\n", reflect.ValueOf(nil))
fmt.Printf("Interface Reflect: %v\n", reflect.ValueOf(nil).IsNil())
第一条会输出 <invalid reflect.Value>,第二条会 Panic,因为:
// IsNil reports whether its argument v is nil. The argument must be
// a chan, func, interface, map, pointer, or slice value; if it is
// not, IsNil panics.
这就是 Go,不爽不要玩。
可运行代码如下:
相关链接:
https://speakerdeck.com/campoy/understanding-nil
我觉得很多人可能没理解我想表达什么,完美符合我对 Go 社区的印象。