102

Currently I'm using this helper function to check for nil and nil interfaces

func isNil(a interface{}) bool {
  defer func() { recover() }()
  return a == nil || reflect.ValueOf(a).IsNil()
}

Since reflect.ValueOf(a).IsNil() panics if the value's Kind is anything other than Chan, Func, Map, Ptr, Interface or Slice, I threw in the deferred recover() to catch those.

Is there a better way to achieve this check? It think there should be a more straight forward way to do this.

  • 8
    I don't understand... Why doesn't a simple `a==nil` work? – Song Gao Nov 20 '12 at 15:38
  • 13
    @SongGao: there are 2 different things the OP is checking: 1) if `a` is the nil interface itself (in which case `a==nil` will be true), or if `a` is a non-nil interface whose underlying value is a `nil` value of channel, function, pointer, or slice type (in which case `a==nil` will be false) – newacct Nov 20 '12 at 19:34
  • 1
    The accepted answer is not correct, I was stuck with the same problem. The right answer is to check every case, unfortunately. https://medium.com/@mangatmodi/go-check-nil-interface-the-right-way-d142776edef1 – Mangat Rai Modi Jan 17 '20 at 11:44

10 Answers10

45

See for example Kyle's answer in this thread at the golang-nuts mailing list.

In short: If you never store (*T)(nil) in an interface, then you can reliably use comparison against nil, no need to use reflection. On the other hand, assigning untyped nil to an interface is always OK.

Dominik Honnef
  • 17,937
  • 7
  • 41
  • 43
zzzz
  • 87,403
  • 16
  • 175
  • 139
  • 7
    what about `[]T(nil)`, `map[T]T(nil)`, `func()(nil)`, and `chan T(nil)`? – newacct Nov 20 '12 at 19:39
  • 37
    This looks like a nefarious bug waiting to happen. – Joel Cornett Feb 02 '17 at 04:16
  • 1
    Sorry for my ignorance, can you explain further what means 'On the other hand, assigning untyped nil to an interface is always OK.' i wonder what that means.. for start, i don't know that nil could be typed or untyped... i believe that it is (nil) an special value for any pointer types – Victor Jun 12 '19 at 20:19
  • 5
    @Victor they just mean that you can store nil in an interface variable. Such as: `var thing interface{}; thing = nil`. That is completely legal. `thing` has a "type" of `interface{}`, but does not have an _underlying_ type. However, you cannot store nil in an untyped variable, like `thing := nil`. Nil is "typed" in that it requires some kind of type to go along with it. Like a nil int pointer, or nil string pointer. You cannot just have a nil pointer to some unknown type without it being an interface. But then, it's kind of typed... It's definitely confusing. – Nathan Lutterman Sep 24 '19 at 01:41
  • 3
    @NathanLutterman thanks your explanation, i get the concept. Still is confusing becase nil is a value not a type (outside golang world at least...). Instaed of "untyped nil" i would propose to use the words "literal nil" as is the value itself placed within a expression, instead of the value placed inside one variable, constanst or function call return value. – Victor Sep 26 '19 at 14:15
  • You can't always enforce that `nil` is not stored in an interface. Think 3rd party libraries and JSON decoding. –  Aug 07 '21 at 07:50
  • It is very easy to run into this by accident, even in your everyday logging code. Example: https://go.dev/play/p/9dk3Ad6PS7P – SOFe Aug 10 '23 at 03:39
31

If neither of the earlier options works for you, the best I could came up so far is:

if c == nil || (reflect.ValueOf(c).Kind() == reflect.Ptr && reflect.ValueOf(c).IsNil())

At least it detects (*T)(nil) cases.

aaa bbb
  • 1,135
  • 11
  • 13
  • 2
    Works as long as `c` is not a typed pointer to a slice etc. In that case, a logic like `reflect.Ptr(reflect.ValueOf(c)) && reflect.ValueOf(c).Elem().IsNil()` is required. And I doubt with that all addional cases are covered then ... – NotX Mar 24 '21 at 18:01
10

Two solutions NOT using reflection:

Copy and paste code into editor at: https://play.golang.org/ to see in action.

  1. Add an "IsInterfaceNil()" function to interface.
  2. Use A "type switch"

Example 1: IsInterfaceNil()

//:Example #1:
//:I prefer this method because the 
//:TakesInterface function does NOT need to know
//:about all the different implementations of
//:the interface.
package main;
import "fmt";

func main()(){

    var OBJ_OK *MyStruct = &( MyStruct{} );
    var NOT_OK *MyStruct = nil;
    
    //:Will succeed:
    TakesInterface( OBJ_OK );
    
    //:Will fail:
    TakesInterface( NOT_OK );

}

func TakesInterface( input_arg MyInterface ){

    if( input_arg.IsInterfaceNil() ){
        panic("[InputtedInterfaceIsNil]");
    }
    
    input_arg.DoThing();
}

type MyInterface interface{
    DoThing()()
    IsInterfaceNil()(bool)
}
type MyStruct struct{}
func(f *MyStruct)DoThing()(){
    fmt.Println("[MyStruct.DoThing]");
}
func(f *MyStruct)IsInterfaceNil()(bool){
    if(nil==f){ return true; }
    return false;
}

Example 2: Type Switch

//:Example #2:
//:This will also work, but the function taking
//:the interface needs to know about all 
//:implementations. This defeats a bit of the
//:decoupling from implementation that an
//:interface offers, but if you are just using
//:interfaces for polymorphism, it's probably
//:an okay way to go. (opinion)
package main;
import "fmt";

func main()(){

    //:Will succeed:
    var OBJ_OK *IMPLMENTS_INTERFACE_01 = 
             &( IMPLMENTS_INTERFACE_01{} );
    TakesInterface( OBJ_OK );
    
    //:Will fail:
    var NOT_OK *IMPLMENTS_INTERFACE_01 = nil;
    TakesInterface( NOT_OK );
}

func TakesInterface( hasDoThing MyInterface ){

    //:THIS WILL NOT WORK:
    if(nil==hasDoThing){
        panic("[This_Error_Message_Will_Never_Happen]");
    }
    
    //:TYPE SWITCH TO THE RESCUE:
    switch v := hasDoThing.(type){
    
        case (*IMPLMENTS_INTERFACE_01): 
        if(nil==v){ panic("[Nil_PTR_01]"); }
        
        case (*IMPLMENTS_INTERFACE_02): 
        if(nil==v){ panic("[Nil_PTR_02]"); }
        
        case (*IMPLMENTS_INTERFACE_03): 
        if(nil==v){ panic("[Nil_PTR_03]"); }
        
        default: 
            panic("[UnsupportedInterface]");
    }
    
    hasDoThing.DoThing();
    
}

type IMPLMENTS_INTERFACE_01 struct{};
type IMPLMENTS_INTERFACE_02 struct{};
type IMPLMENTS_INTERFACE_03 struct{};
func (f *IMPLMENTS_INTERFACE_01)DoThing()(){
    fmt.Println( "DoingTheThing_01" );
}
func (f *IMPLMENTS_INTERFACE_02)DoThing()(){
    fmt.Println( "DoingTheThing_02" );
}
func (f *IMPLMENTS_INTERFACE_03)DoThing()(){
    fmt.Println( "DoingTheThing_03" );
}

type MyInterface interface{
    DoThing()()
}

Update: After implementing in my code base, I found #2 (type switch) to be best solution. Specifically because I DON'T want to EDIT the glfw.Window struct in the bindings library I am using. Here is a paste-bin of my use-case. Apologies for my non-standard coding style. https://pastebin.com/22SUDeGG

425nesp
  • 6,936
  • 9
  • 50
  • 61
KANJICODER
  • 3,611
  • 30
  • 17
  • 6
    This doesn't solve the problem for plain interface{}, which is what the question is about – Jon Watte Jun 14 '18 at 17:48
  • I agree. It's a workaround. I wasn't happy with the accepted answer of "In short: [ ... ] never store (*T)(nil) in an interface" – KANJICODER Jul 25 '18 at 18:39
2

For Golang 1.16+

func IsNilish(val any) bool {
    if val == nil {
        return true
    }

    v := reflect.ValueOf(val)
    k := v.Kind()
    switch k {
    case reflect.Chan, reflect.Func, reflect.Map, reflect.Pointer,
        reflect.UnsafePointer, reflect.Interface, reflect.Slice:
        return v.IsNil()
    }

    return false
}
Alex Medveshchek
  • 501
  • 4
  • 12
0

This is the interface definition for this exmaple solution:

package checker

import (
    "errors"

    "github.com/rs/zerolog"
)

var (
    // ErrNilChecker returned if Check invoked on a nil checker
    ErrNilChecker = errors.New("attempted Check with nil Checker")

    // ErrNilLogger returned if the Check function is provide a nil logger
    ErrNilLogger = errors.New("nil logger provided for Check")
)

// Checker defines the interface
type Checker interface {
    Check(logger *zerolog.Logger) error
}

One of our Checker implementations supports aggregation of Checkers. But testing uncovered the same issue as this thread. This solution uses the reflect package if the simple nil check fails, leveraging the reflect.Value type to resolve the question.

// AggregateChecker implements the Checker interface, and
//  supports reporting the results of applying each checker
type AggregateChecker struct {
    checkers []Checker
}

func (ac *AggregateChecker) Add(aChecker Checker) error {
    if aChecker == nil {
        return ErrNilChecker
    }

    // It is possible the interface is a typed nil value
    // E.g. checker := (&MyChecker)(nil)
    t := reflect.TypeOf(aChecker)
    if reflect.ValueOf(aChecker) == reflect.Zero(t) {
        return ErrNilChecker
    }

    ac.checkers = append(ac.checkers, aChecker)
    return nil
}
0

If you are looking for a comprehensive solution this would be a perfect one
Adopted from https://github.com/thoas/go-funk

// IsEmpty returns if the object is considered as empty or not.
func IsEmpty(obj interface{}) bool {
    if obj == nil || obj == "" || obj == false {
        return true
    }

    for _, v := range numericZeros {
        if obj == v {
            return true
        }
    }

    objValue := reflect.ValueOf(obj)

    switch objValue.Kind() {
    case reflect.Map:
        fallthrough
    case reflect.Slice, reflect.Chan:
        return objValue.Len() == 0
    case reflect.Struct:
        return reflect.DeepEqual(obj, ZeroOf(obj))
    case reflect.Ptr:
        if objValue.IsNil() {
            return true
        }

        obj = redirectValue(objValue).Interface()

        return reflect.DeepEqual(obj, ZeroOf(obj))
    }

    return false
}
AH.Pooladvand
  • 1,944
  • 2
  • 12
  • 26
0

Similar to AH.Pooladvand's answer, but only check if it is nil.

func IsNil(input interface{}) bool {
    if input == nil {
        return true
    }
    kind := reflect.ValueOf(input).Kind()
    switch kind {
    case reflect.Ptr, reflect.Map, reflect.Slice, reflect.Chan:
        return reflect.ValueOf(input).IsNil()
    default:
        return false
    }
}
-1
func main() {
    var foo interface{}
    fmt.Println(reflect.TypeOf(foo) == nil) // true

    type Bar struct{}
    var bar *Bar
    fmt.Println(reflect.TypeOf(bar) != nil) // true
}
F566
  • 475
  • 4
  • 8
-1

May be you try use an error in the function that populates the interface:

package a

func getObj() (obj *someObject, err error) {
   obj = db.getA()
   if obj == nil {
      err = fmt.Errorf("Some error")
   }
   return
}

package b

import a

var i interface{}

i, err = a.getObj()
if err != nil {
   // catch err
} else {
   // do next step
}
-2

consider inboundData to be your interface

use the len() function to check if there are data in the interface

if inboundData != nil && len(inboundData) > 0 {
    // ... do stuff | data is present
} else {
    // ... data is not present
}
ajaidanial
  • 5
  • 1
  • 1
  • 1.) This does not work with `interfaces{}`. I suppose `inboundData` is a slice or a map in your case. 2.) It does not tell when something is `nil` and when a map or slice is just empty. 3.) For maps and slices there's no need at all to do an `nil`-check before `len(...)` if you want just to know whether there's data or not. Just do `len(...)` in that case. – NotX Mar 24 '21 at 18:07