6

当我偶然发现这种明显的不一致时,我正在做一个简单的链表接口来了解 Go 接口。nextT总是 nil 但返回值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()我得到

true
false

有了它,我得到了预期的结果

true
true

我是否发现了一个错误,或者出于某种原因,这个惊喜是故意的?使用 zip 安装在带有 Go 版本 1 的 Windows 上运行(无 MSI)

4

1 回答 1

8

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

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

查看 Go 标准库中的container/list包,了解更惯用的通用链表实现。还有一篇 Russ Cox 的优秀文章,其中包含对 Go 接口类型的深入解释。

于 2012-06-13T22:38:23.977 回答