Reputation:
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.
Upvotes: 108
Views: 140787
Reputation: 31
Another simple but "hacky" option (not recommended for production), apart from the previous answers is to use the fmt
package, that uses reflection to determine what to print:
https://go.dev/play/p/lUROP8lxwxF
fmt.Sprint(value) == "<nil>"
It will work for most use cases, except:
fmt
uses the [] notation for slices so it won't work"<nil>"
value, will return a false positiveUpvotes: 0
Reputation: 11
fwiw, here's a reference to the go FAQ explaining why nil interface checks don't work as expected:
https://go.dev/doc/faq#nil_error
An (unusual) workaround which might be useful if you have a bunch of pointer types all implementing the same interface ( though it doesn't help for the question of bare interface{}
s )... use generics to wrap the pointers with a helper:
// helper struct to track whether an implementation was nil
type SomeRef struct {
SomeInterface
IsNil bool
}
// generic helper to create the struct
func Ref[P any,
I interface {
*P
SomeInterface
}](in *P) SomeRef {
return SomeRef{I(in), in == nil}
}
// function takes "refs" not the raw interfaces
func DoSomething(refs ...SomeRef) {
for _, el := range refs {
// tests for nil...
if !el.IsNil {
el.CallSomeInterfaceFunction()
}
}
}
// assuming A, B, and C pointers all implement SomeInterface....
func Example(a* A, b *B, c *C) {
// you can pass refs so the callee can test for nil
DoSomething(Ref(a), Ref(b), Ref(c))
}
an example program here:
https://go.dev/play/p/Q6rNlM2KiVm
Upvotes: 0
Reputation: 3885
Two solutions NOT using reflection:
Copy and paste code into editor at: https://play.golang.org/ to see in action.
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
Upvotes: 10
Reputation: 655
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
}
Upvotes: 10
Reputation: 49
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
}
}
Upvotes: -1
Reputation: 2059
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
}
Upvotes: -1
Reputation: 37
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
}
Upvotes: -2
Reputation: 3
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
}
Upvotes: -3
Reputation: 1
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
}
Upvotes: -1
Reputation: 1275
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.
Upvotes: 34
Reputation: 91253
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.
Upvotes: 51