英文:
Inconsistent nil for pointer receiver (Go bug?)
问题
我正在做一个简单的链表接口来学习Go接口,当我遇到这个明显的不一致时。nextT
始终为nil,但next()
的返回值不是。
package main
import (
"fmt"
)
type LinkedList interface {
next() LinkedList
}
type T struct {
nextT *T
}
func (t *T) next() LinkedList {
//取消注释以查看差异
/*if t.nextT == nil {
return nil
}*/
return t.nextT//这是nil!
}
func main() {
t := new(T)
fmt.Println(t.nextT == nil)
var ll LinkedList
ll = t
fmt.Println(ll.next() == nil)//为什么这不是nil?
}
没有在next()
中进行nil检查(我不应该这样做)时,我得到:
true
false
有了它,我得到了预期的结果:
true
true
我是否发现了一个bug,还是这种意外是有意为之的?在Windows上运行,使用Go版本1,使用zip安装(没有MSI)。
英文:
I was doing a simple linked list interface to learn about Go interfaces when I stumbled upon this apparent inconsistency. nextT
is always nil but the return value of next()
isn't.
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?
}
Without the nil check (which I shouldn't have to do) in next()
I get
true
false
With it I get the expected result
true
true
Have I discovered a bug or is this surprise intentional for some reason? Running on Windows with Go version 1 using the zip installation (no MSI)
答案1
得分: 8
不,那不是一个bug。在Go中,接口基本上是一对两个值:类型信息和指向实际数据的指针。将未类型化的值nil
赋给一个接口,也就是接口的零值,意味着该接口既没有类型信息,也没有指向任何存储的数据的指针。
另一方面,将*T
指针赋给一个接口,将相应地设置类型信息,并让数据指针指向该指针。在这种情况下,接口不再是nil
,因为您已经存储了一个具体类型和具体值。在您的情况下,存储的值恰好是nil
。您可以使用类型断言(或reflect包)来检查接口是否具有特定的类型。类型断言只有在类型信息匹配时才会成功(如果之前将nil赋给该接口,则显然永远不可能)。如果测试成功,您将得到一个*T
,但是该指针可能仍然具有值nil
(对于该类型来说,这是一个有效的值)。
请查看Go标准库中的container/list包,以查看更典型的通用链表实现。还有一篇由Russ Cox撰写的优秀文章,其中详细解释了Go的接口类型。
英文:
No, that's not a bug. An interface in Go, is basically a pair of two values: a type information and a pointer to the actual data. Assigning the untyped value nil
to an interface, which also happens to be the zero value of an interface, means that the interface has neither a type information nor a pointer to any data stored.
On the other hand, assigning a *T
pointer to an interface, will set the type information accordingly and let the data pointer point to this pointer. In that case, the interface isn't nil
anymore, because you have stored a specific type with a specific value inside. In your case it just happens that the value you have stored is nil. You can use a type assertion (or the reflect package) to check if an interface has specific type assigned. The type assertion will only succeed if the type information matches (which can be obviously never be the case if you have assigned nil to that interface before). If the test succeeds, you will get a *T
back, but this pointer might still have the value nil
(which is a valid value for that type).
Take a look at the container/list package in the Go standard library to see a more idiomatic general linked-list implementation. There is also an excellent article by Russ Cox that contains an in-depth explanation of Go's interface type.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论