There is some interview question may ask whether nil == nil be true in GoLang. Wil it be true. false or compilation error? To know the answer, some knowledge about nil in GoLang needs to be explained first.
nil definition
According to Go's official documentation, the definition of nil is
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
nil is the zero value of types like pointer, channel, func, interface, map or slice. Itself is NOT a GoLang keyword.
Deep dive nil
nil is not keyword
nil can be defined as variable name and can have value assigned to it. See below:
func main() {
nil := "this is nil"
fmt.Println(nil)
}
// result
this is nil
Here nil is defined as a string variable.
func main() {
nil := "this is nil"
fmt.Println(nil)
var slice []string = nil
fmt.Println(slice)
}
// result
# command-line-arguments
./nil.go:10:6: cannot use nil (type string) as type []string in assignment
From the compilation, nil is just a normal string variable. This kind of definition is not recommended.
nil's default type
Normally some pre-defined identifiers have default type associated, for example itoa
's default type is int
. So what is the default type of nil
?
func main() {
const val1 = iota
fmt.Printf("%T\n",val1)
var val2 = nil
fmt.Printf("%T\n",val2)
}
// result
# command-line-arguments
./nil.go:10:6: use of untyped nil
This code snippet produces compilation error. nil doesn't have default type, its type is undefined which means there should be enough information to provide to derive its type.
Comparison of nil
There are two scenarios for nil comparison:
- nil identifier comparison
- nil value comparison
Regarding the identifier comparison, let's take a look at the result from the code snippet from the beginning.
# command-line-arguments
./nil.go:8:18: invalid operation: nil == nil (operator == not defined on nil)
It means the behavior is undefined for direct nil == nil comparison, hence it's not allowed to do nil == nil comparison.
Regarding nil value comparison, the type will be determined based on the context, the value comparison is indeed to compare different types of nil. Hence there are two types of comparison: same nil type and different nil type.
Same nil type
func main() {
// pointer
fmt.Println((*int64)(nil) == (*int64)(nil))
// channel
fmt.Println((chan int)(nil) == (chan int)(nil))
// func
fmt.Println((func())(nil) == (func())(nil))
// interface
fmt.Println((interface{})(nil) == (interface{})(nil))
// map
fmt.Println((map[string]int)(nil) == (map[string]int)(nil))
// slice
fmt.Println(([]int)(nil) == ([]int)(nil))
}
Result:
# command-line-arguments
./nil.go:13:28: invalid operation: (func())(nil) == (func())(nil) (func can only be compared to nil)
./nil.go:17:36: invalid operation: (map[string]int)(nil) == (map[string]int)(nil) (map can only be compared to nil)
./nil.go:19:27: invalid operation: ([]int)(nil) == ([]int)(nil) (slice can only be compared to nil)
From result, func, map and slice can only be compared with nil identifier.
Different nil type
func main() {
var ptr *int64 = nil
var cha chan int64 = nil
var fun func() = nil
var inter interface{} = nil
var ma map[string]string = nil
var slice []int64 = nil
fmt.Println(ptr == cha)
fmt.Println(ptr == fun)
fmt.Println(ptr == inter)
fmt.Println(ptr == ma)
fmt.Println(ptr == slice)
fmt.Println(cha == fun)
fmt.Println(cha == inter)
fmt.Println(cha == ma)
fmt.Println(cha == slice)
fmt.Println(fun == inter)
fmt.Println(fun == ma)
fmt.Println(fun == slice)
fmt.Println(inter == ma)
fmt.Println(inter == slice)
fmt.Println(ma == slice)
}
Result:
# command-line-arguments
./nil.go:14:18: invalid operation: ptr == cha (mismatched types *int64 and chan int64)
./nil.go:15:18: invalid operation: ptr == fun (mismatched types *int64 and func())
./nil.go:17:18: invalid operation: ptr == ma (mismatched types *int64 and map[string]string)
./nil.go:18:18: invalid operation: ptr == slice (mismatched types *int64 and []int64)
./nil.go:20:18: invalid operation: cha == fun (mismatched types chan int64 and func())
./nil.go:22:18: invalid operation: cha == ma (mismatched types chan int64 and map[string]string)
./nil.go:23:18: invalid operation: cha == slice (mismatched types chan int64 and []int64)
./nil.go:25:18: invalid operation: fun == inter (operator == not defined on func)
./nil.go:26:18: invalid operation: fun == ma (mismatched types func() and map[string]string)
./nil.go:27:18: invalid operation: fun == slice (mismatched types func() and []int64)
./nil.go:27:18: too many errors
Other tips about nil
nil interface
func main() {
err := Todo()
fmt.Println(err == nil)
}
type Err interface {
}
type err struct {
Code int64
Msg string
}
func Todo() Err {
var res *err
return res
}
// result
false
interface has its own structure, it consists both type and value and it will be considered as nil if only both its type and value are nil.
nil map
func main() {
var m map[string]string
fmt.Println(m["asoong"])
m["asong"] = "Golang梦工厂"
}
// result
panic: assignment to entry in nil map
goroutine 1 [running]:
main.main()
go/src/asong.cloud/Golang_Dream/code_demo/slice_demo/nil.go:10 +0xed
A nil map can be read but cannot be written.
nil channel
func main() {
var cha chan int
close(cha)
}
panic: close of nil channel
goroutine 1 [running]:
main.main()
/go/src/asong.cloud/Golang_Dream/code_demo/slice_demo/nil.go:5 +0x2a
A nil channel cannot be closed, otherwise a panic would happen.
nil slice
func main() {
var slice []int64 = nil
fmt.Println(len(slice))
fmt.Println(cap(slice))
for range slice{
}
fmt.Println(slice[0])
}
// result
0
0
panic: runtime error: index out of range [0] with length 0
goroutine 1 [running]:
main.main()
/go/src/asong.cloud/Golang_Dream/code_demo/slice_demo/nil.go:14 +0xf2
A nil slice cannot be accessed with index, but other operations on nil slice can be performed such as len(), cap().
Reference: é¢è¯•å®˜ï¼šä¸¤ä¸ªnil比较结果是什么? (qq.com)
So you didn't understand in go that names are just types and to use them they have to be assigned a value? And then you went to town with the == with these types without values....... Why?
"Types need values" - what is so complicated about that? I honestly don't understand?