Today's Question:  What does your personal desk look like?        GIVE A SHOUT

Will nil == nil be true in GoLang

  sonic0002        2021-08-08 02:54:15       5,711        2    

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)

GOLANG  NIL  NIL EXPLANATION 

Share on Facebook  Share on Twitter  Share on Weibo  Share on Reddit 

  RELATED


  2 COMMENTS


Anonymous [Reply]@ 2021-08-10 09:16:08

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? 

Anonymous [Reply]@ 2021-09-24 23:31:41

types need to be assigned values? what does that mean. if i declared a variable and if i don't assign value to it, then it will use default value.

How does it relate to what u r saying?