通过Go中的反射快速检测空值

时间:2012-12-16 13:37:50

标签: reflection go

我有一个int / string / bool / etc ..值存储在interface{}中,并想确定它是否未初始化,这意味着它有一个值

  • 0
  • ""
  • false
  • nil

我该如何检查?

4 个答案:

答案 0 :(得分:55)

据我所知,你想要的东西是:

func IsZeroOfUnderlyingType(x interface{}) bool {
    return x == reflect.Zero(reflect.TypeOf(x)).Interface()
}

在谈论界面和nil时,人们总是对两种截然不同且无关的事情感到困惑:

  1. 一个nil接口值,它是一个没有基础值的接口值。这是接口类型的零值。
  2. nil接口值(即它具有基础值),但其基础值是其基础类型的零值。例如基础值是nil地图,nil指针或0数字等
  3. 我的理解是你在问第二件事。


    更新:由于上述代码使用的是==,因此不适用于 compare 的类型。我相信使用reflect.DeepEqual()会使其适用于所有类型:

    func IsZeroOfUnderlyingType(x interface{}) bool {
        return reflect.DeepEqual(x, reflect.Zero(reflect.TypeOf(x)).Interface())
    }
    

答案 1 :(得分:3)

interface{}类型的zero value *仅为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

*:[Q]当分配内存来存储值时,无论是通过声明还是调用make或new,并且没有提供显式初始化,内存都会被赋予默认初始化。这种值的每个元素都设置为其类型的零值:布尔值为false,整数为0,浮点数为0.0,字符串为“”,指针,函数,接口,切片,通道和映射为nil [ / Q]

答案 2 :(得分:1)

@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))
}

答案 3 :(得分:1)

Go 1.13(2019年第三季度)应简化检测过程:

  

新的Value.IsZero()方法报告一个Value是否是其类型的零值。

它在src/reflect/value.gocommit c40bffdCL 171337中实现,解决了issue 7501

请参见playground example(只要支持Go 1.13)