当我偶然发现这种明显的不一致时,我正在做一个简单的链表接口来了解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?
}
Run Code Online (Sandbox Code Playgroud)
next()我得到的没有零检查(我不应该这样做)
true
false
Run Code Online (Sandbox Code Playgroud)
有了它,我得到了预期的结果
true
true
Run Code Online (Sandbox Code Playgroud)
我是否因为某种原因发现了一个错误或者这个意外的故意?使用zip安装在没有MSI的Go版本1的Windows上运行
不,那不是错误.Go中的接口基本上是一对两个值:类型信息和指向实际数据的指针.将无类型值分配nil给接口(也恰好是接口的零值)意味着接口既没有类型信息也没有指向存储的任何数据的指针.
另一方面,指定一个*T接口的指针,将相应地设置类型信息,并让数据指针指向该指针.在这种情况下,界面nil不再存在,因为您已经存储了具有特定值的特定类型.在你的情况下,你所存储的值恰好是零.您可以使用类型断言(或反射包)来检查接口是否已分配特定类型.只有在类型信息匹配时,类型断言才会成功(如果您之前已将nil分配给该接口,则显然不会出现这种情况).如果测试成功,您将*T返回,但此指针可能仍具有该值nil(该类型的有效值).
查看Go标准库中的容器/列表包,以查看更具惯用性的常规链接列表实现.还有一篇由Russ Cox 撰写的优秀文章,其中包含对Go的界面类型的深入解释.