http://play.golang.org/p/_GP3RZTh4Q
package main
import "fmt"
type TesterInterface interface{
Yell()
}
type Tester struct{}
func (t Tester) Yell() {
fmt.Println("HELLO")
}
func main() {
var t TesterInterface
t = Tester{}
t.Yell()
t = nil
t.Yell()
}
我希望编译器抱怨第19行(t = nil
),因为nil
没有实现Yell()
,但程序运行并提供以下输出:
HELLO
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0xffffffff addr=0x0 pc=0x201a9]
goroutine 1 [running]:
runtime.panic(0xef060, 0x1b3d44)
/tmp/sandbox/go/src/pkg/runtime/panic.c:266 +0xe0
runtime.panicstring(0x1b3d44, 0x1b85)
/tmp/sandbox/go/src/pkg/runtime/panic.c:489 +0x120
runtime.sigpanic()
/tmp/sandbox/go/src/pkg/runtime/os_nacl.c:254 +0x80
main.main()
/tmpfs/gosandbox-229cdcdf_329829af_705be907_f12cf4dc_ed51e32e/prog.go:20 +0xa9
runtime.main()
/tmp/sandbox/go/src/pkg/runtime/proc.c:220 +0x1c0
runtime.goexit()
/tmp/sandbox/go/src/pkg/runtime/proc.c:1394
goroutine 2 [syscall]:
runtime.notetsleepg(0xfeefdf88, 0x0, 0xf8475800, 0xd)
/tmp/sandbox/go/src/pkg/runtime/lock_sema.c:254 +0xa0
runtime.MHeap_Scavenger()
/tmp/sandbox/go/src/pkg/runtime/mheap.c:463 +0xc0
runtime.goexit()
/tmp/sandbox/go/src/pkg/runtime/proc.c:1394
created by runtime.main
/tmp/sandbox/go/src/pkg/runtime/proc.c:179
[process exited with non-zero status]
Program exited.
为什么编译器认为将nil
分配给接口是合法的?
此外,来自Go-docs:
接口类型的变量可以存储任何类型的值,其方法集是接口的任何超集。
“nil”如何包含作为TesterInterface
超集的方法集?文档继续说
接口类型的未初始化变量的值为nil。
但这似乎与第一个陈述相矛盾。
答案 0 :(得分:6)
The Go Programming Language Specification
当分配内存来存储值时,通过a 声明或调用make或new,并且没有明确的初始化 如果提供,则为存储器提供默认初始化。每 将此类值的元素设置为其类型的零值:false 对于布尔值,0表示整数,0.0表示浮点数,“”表示字符串,nil 用于指针,函数,接口,切片,通道和地图。
值nil
对接口类型变量有效,因为它是接口类型的零值。
Go Data Structures: Interfaces文章描述了接口值的实现。
答案 1 :(得分:5)
当你提出像#34这样的问题时总是很冒险;为什么编译器认为这是合法的......"像往常一样,答案是因为它是语言,每个接口都接受nil
值。但是还有更多的方面:接口的实现,以及如果不是这样,Go将如何工作。
从后者开始,如果nil
不是接口的合法值,请考虑问题。你会如何取代常见的习语:
func Something() error {
...
return nil
}
这取决于nil
是有效的error
这一事实。 同样,指针满足接口是很常见的。如果 nil
也不满足接口,那么如何返回nil
指针?请记住,nil
只是一个值。
对于实现,请参阅Why is my nil error value not equal to nil?关键点是接口由类型和值的元组组成,对于每个接口,元组(nil, nil)
都有效。
我假设您同意&#34;键入 < / p> <击>
nil
&#34; (即某个特定指针类型的nil
应该可以分配给由其指针类型实现的接口,对吗?所以接口必须被视为nil
,并且必须nil
- 以与nil
完全相同的方式检查它们 - 检查指针。因此,排除无类型的nil
没有安全上的好处,但是您可以打破许多有用的界面(例如返回&#34;没有错误&#34;)。
(对于这最后一部分有轻微的细节。再仔细阅读&#34;为什么我的nil错误值不等于nil?&#34;并且你&#39;我会意识到你不能简单地检查一个包含类型nil值的接口。你只能通过将接口断言为其底层指针类型或使用反射来实现这一点。这并没有显着改变这一点,但我并不想掩盖这个问题。)
修改强>
根据@ newacct的评论,发现了一些无关紧要的观点。
彼得的答案也非常重要。每种类型必须具有零值。接口的零值还有nil
?