GO interface{} and nil value

Checking for a nil value is very common in GO programs so it is important to know the difference between checking nil on a given type and checking nil on an interface{} object.

Let's start with an example:

package main

import "fmt"

func GiveMeANil(value *string) {
  if value == nil {
   fmt.Println("Thank you my friend! I really needed it!")
  } else {
   fmt.Println("Sorry mate, but I really need a nil...")
  }
}

func main() {
  // explicitly assigning `nil` for clarity
  var nilString *string = nil 
  GiveMeANil(nilString)
  GiveMeANil(nil)
}

==== OUTPUT ====
Thank you my friend! I really needed it!
Thank you my friend! I really needed it!

No surprises. The code is doing exactly what we were expecting it to do. However, now we notice that the GiveMeANil function is so useful that we want it to work with any type, so we decide to change the code using interface{}

package main

import "fmt"

func GiveMeANil(value interface{}) {
  if value == nil {
   fmt.Println("Thank you my friend! I really needed it!")
  } else {
   fmt.Println("Sorry mate, but I really need a nil...")
  }
}

func main() {
  // explicitly assigning `nil` for clarity
  var nilString *string = nil 
  GiveMeANil(nilString)
  GiveMeANil(nil)
}

==== OUTPUT ====
Sorry mate, but I really need a nil...
Thank you my friend! I really needed it!

The output has changed. For some reason, GO is saying the first nil is not a nil. Why?

Explanation

The reason is that an interface{} internally is an object composed of 2 attributes (type and the value) and it is considered nil only when both attributes are nil. With the first call (GiveMeANil(nilString)) value will be nil while type will be string*, hence the interface{} is not nil. With the second call, on the other hand, both value and type will be nil, hence the interface{} object is nil.

Solution

You will think: "Hmm... ok, I understood, but... how do I check an interface{} for nil then?" If you don't know the real underlying type or if you don't want to downcast, you need to use the reflection.

Here is the full working code:

package main

import (
    "fmt"
    "reflect"
)

func GiveMeANil(value interface{}) {
    if value == nil || reflect.ValueOf(value).IsNil() {
        fmt.Println("Thank you my friend! I really needed it!")
    } else {
        fmt.Println("Sorry mate, but I really need a nil...")
    }
}

func main() {
    var nilString *string = nil // explicitly assigning `nil` to make it clear
    GiveMeANil(nilString)
    GiveMeANil(nil)
}