当我偶然发现这种明显的不一致时,我正在做一个简单的链表接口来了解Go接口。 nextT
始终为零,但next()
的返回值不是。
package main
import (
"fmt"
)
type LinkedList interface {
next() LinkedList
}
type T struct {
nextT *T
}
func (t *T) next() LinkedList {
//uncomment to see the difference
/*if t.nextT == nil {
return nil
}*/
return t.nextT//this is nil!
}
func main() {
t := new(T)
fmt.Println(t.nextT == nil)
var ll LinkedList
ll = t
fmt.Println(ll.next() == nil)//why isn't this nil?
}
在next()
中没有nil检查(我不应该这样做),我得到了
true
false
有了它,我得到了预期的结果
true
true
我是否发现了一个错误,或者出于某种原因这是一个意外的故意?使用zip安装(无MSI)在Go版本1的Windows上运行
答案 0 :(得分:7)
不,那不是错误。 Go中的接口基本上是一对两个值:类型信息和指向实际数据的指针。将无类型值nil
分配给接口(也恰好是接口的零值)意味着接口既没有类型信息也没有指向存储的任何数据的指针。
另一方面,为接口分配*T
指针,将相应地设置类型信息,并让数据指针指向该指针。在这种情况下,接口不再是nil
,因为您已经存储了具有特定值的特定类型。在你的情况下,你所存储的值恰好是零。您可以使用类型断言(或reflect包)来检查接口是否分配了特定类型。只有在类型信息匹配时,类型断言才会成功(如果您之前已将nil分配给该接口,则显然不会出现这种情况)。如果测试成功,您将返回*T
,但此指针仍可能具有值nil
(这是该类型的有效值)。
查看Go标准库中的container/list包,以查看更具惯用性的常规链接列表实现。 Russ Cox还有一个excellent article,其中包含对Go接口类型的深入解释。