指针接收器的nil不一致(Go bug?)

时间:2012-06-13 21:29:21

标签: linked-list go

当我偶然发现这种明显的不一致时,我正在做一个简单的链表接口来了解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上运行

1 个答案:

答案 0 :(得分:7)

不,那不是错误。 Go中的接口基本上是一对两个值:类型信息和指向实际数据的指针。将无类型值nil分配给接口(也恰好是接口的零值)意味着接口既没有类型信息也没有指向存储的任何数据的指针。

另一方面,为接口分配*T指针,将相应地设置类型信息,并让数据指针指向该指针。在这种情况下,接口不再是nil,因为您已经存储了具有特定值的特定类型。在你的情况下,你所存储的值恰好是零。您可以使用类型断言(或reflect包)来检查接口是否分配了特定类型。只有在类型信息匹配时,类型断言才会成功(如果您之前已将nil分配给该接口,则显然不会出现这种情况)。如果测试成功,您将返回*T,但此指针仍可能具有值nil(这是该类型的有效值)。

查看Go标准库中的container/list包,以查看更具惯用性的常规链接列表实现。 Russ Cox还有一个excellent article,其中包含对Go接口类型的深入解释。