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)
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With