我有一个存储在 interface{}
中的 int
/string
/bool
/等值,并想确定它是否未初始化,也就是它的值为以下之一:
0
""
false
- 或者
nil
我该如何检查这个值?
我有一个存储在 interface{}
中的 int
/string
/bool
/等值,并想确定它是否未初始化,也就是它的值为以下之一:
0
""
false
nil
我该如何检查这个值?
据我所理解,你想要类似于以下的东西:
func IsZeroOfUnderlyingType(x interface{}) bool {
return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}
当谈论接口和nil
时,人们经常会混淆两个非常不同且无关的事情:nil
接口值,即没有底层值的接口值。这是接口类型的零值。
2. 非nil
接口值(即它具有底层值),但其底层值是其底层类型的零值。例如,底层值是nil
地图、nil
指针或0数字等。==
,因此对于不可比较的类型不起作用。我认为改用reflect.DeepEqual()
将使其适用于所有类型。func IsZeroOfUnderlyingType(x interface{}) bool {
return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
}
x == nil || x == reflect.Zero(reflect.TypeOf(x)).Interface()
,否则在输入为 nil
时会引发异常。 - user187676nil
接口本身,那么是的,你应该添加它。但在问题中,你说接口内存储了int/string/bool等类型。 - newacctmap[string]string
失败。除了强制转换和检查 len
之外,有没有其他方法可以支持映射? - chakritGo 1.13(2019年第3季度)应该简化了该检测过程:
新的
Value.IsZero()
方法报告一个值是否为其类型的零值。
它是在src/reflect/value.go
中实现的,来自c40bffd提交和CL 171337,解决了问题7501
请参见示例(仅当支持Go 1.13时)
var p *string
v := reflect.ValueOf(p)
fmt.Printf("1.13 v.IsZero()='%v' vs. IsZero(v)='%v'\n", v.IsZero(), IsZero(v))
// Ouput:
// 1.13 v.IsZero()='true' vs. IsZero(v)='true'
然而:
v = v.Elem()
fmt.Printf("1.13 v.Elem().IsZero()='%v' vs. IsZero(v.Elem())='%v'\n", v.IsZero(), IsZero(v))
// Panic:
//
// panic: reflect: call of reflect.Value.IsZero on zero Value
如问题46320中所解释的:
您描述的问题是由Go中接口类型的性质以及reflect包建立在接口类型上这一事实引起的。
接口类型的值始终描述另一个值。
当您将接口类型的值传递给reflect.ValueOf
时,您会得到一个反射对象来描述那个其他值,而不是接口类型的值。要使用
reflect
包处理interface
值,通常需要使用指针。这与
IsZero()
无关,这只是reflect
包的工作原理。
package main import ( "fmt" "reflect" ) func main() { var c interface{} fmt.Println(reflect.ValueOf(&c).Elem().Kind()) fmt.Println(reflect.ValueOf(&c).Elem().IsZero()) }
零值*在类型interface{}
中只是nil
,而不是0
、""
或false
。
package main
import "fmt"
func main() {
var v interface{}
fmt.Println(v == nil, v == 0, v == "", v == false)
}
(还有 http://play.golang.org/p/z1KbX1fOgB)
输出
true false false false
interface{}
的零值与 nil
相等。 - zzzzinterface{}
的零值,而是比较一个 interface{}
类型的参数,该参数携带了其中一个传递的值。除了未指定类型的 nil
之外,所有这些值都不是零值。你所说的“空/未初始化”到底是什么意思?它似乎并不等同于零值,那它又是什么呢? - zzzz@newacct的答案无法检测原始零值,调用reflect.Value.Interface()
会导致错误。它可以使用reflect.Value.IsValid()
进行检查。
// 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
更新方法:
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))
}