黑一下 golang

1,372 阅读1分钟
原文链接: zhuanlan.zhihu.com

看看下面的代码。

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,不爽不要玩。

可运行代码如下:

Go Playground

相关链接:

speakerdeck.com/campoy/

我觉得很多人可能没理解我想表达什么,完美符合我对 Go 社区的印象。