I have a int
/string
/bool
/etc.. value stored in an interface{}
and want to determine if it's uninitialized, meaning that it has a value of either
0
""
false
nil
How do I check this?
From what I understand, you want something like:
func IsZeroOfUnderlyingType(x interface{}) bool {
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}
When talking about interfaces and nil
, people always get confused with two very different and unrelated things:
nil
interface value, which is an interface value that doesn't have an underlying value. This is the zero value of an interface type.nil
interface value (i.e. it has an underlying value), but its underlying value is the zero value of its underlying type. e.g. the underlying value is a nil
map, nil
pointer, or 0 number, etc.It is my understanding that you are asking about the second thing.
Update: Due to the above code using ==
, it won't work for types that are not comparable. I believe that using reflect.DeepEqual()
instead will make it work for all types:
func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
The zero value* of type interface{}
is only nil
, not 0
or ""
or false
.
package main
import "fmt"
func main() {
var v interface{}
fmt.Println(v == nil, v == 0, v == "", v == false)
}
(Also http://play.golang.org/p/z1KbX1fOgB)
Output
true false false false
*: [Q]When memory is allocated to store a value, either through a declaration or a call of make or new, and no explicit initialization is provided, the memory is given a default initialization. Each element of such a value is set to the zero value for its type: false for booleans, 0 for integers, 0.0 for floats, "" for strings, and nil for pointers, functions, interfaces, slices, channels, and maps.[/Q]
@newacct's answer can't detect raw zero value, calling reflect.Value.Interface()
on which will cause error. It can use reflect.Value.IsValid()
to check that.
// IsValid reports whether v represents a value.
// It returns false if v is the zero Value.
// If IsValid returns false, all other methods except String panic.
// Most functions and methods never return an invalid value.
// If one does, its documentation states the conditions explicitly.
func (v Value) IsValid() bool
Update the methods:
func IsZero(v reflect.Value) bool {
return !v.IsValid() || reflect.DeepEqual(v.Interface(), reflect.Zero(v.Type()).Interface())
}
func TestIsZero(t *testing.T) {
var p *string
v := reflect.ValueOf(p)
assert.Equal(t, true, v.IsValid())
assert.True(t, IsZero(v))
assert.Equal(t, uintptr(0), v.Pointer())
v = v.Elem()
assert.Equal(t, false, v.IsValid())
assert.True(t, IsZero(v))
}
Go 1.13 (Q3 2019) should simplify that detection process:
The new
Value.IsZero()
method reports whether a Value is the zero value for its type.
It is implemented in src/reflect/value.go
, from commit c40bffd and CL 171337, resolving issue 7501
See playground example (as soon as Go 1.13 is supported)