如何知道任意类型的变量在Golang中是否为零



因为不是所有类型都是可比较的,例如slice。所以我们不能这样做

var v ArbitraryType
v == reflect.Zero(reflect.TypeOf(v)).Interface()

Go 1.13在reflect包中引入了Value.IsZero方法。以下是使用它检查零值的方法:

if reflect.ValueOf(v).IsZero() {
    // v is zero, do something
}

除了基本类型,它还适用于Chan、Func、Array、Interface、Map、Ptr、Slice、UnsafePointer和Struct。

正如Peter Noyes所指出的,你只需要确保你不是在比较一个不可比较的类型。幸运的是,这是非常简单的reflect包:

func IsZero(v interface{}) (bool, error) {
    t := reflect.TypeOf(v)
    if !t.Comparable() {
        return false, fmt.Errorf("type is not comparable: %v", t)
    }
    return v == reflect.Zero(t).Interface(), nil
}

这取决于当v是一个接口时你想要什么行为(对于其他类型它是相同的):

  • reflect.ValueOf(v).IsZero()检查接口中框入的值是否为零
  • reflect.ValueOf(&v).Elem().IsZero()检查接口变量是否为零

示范(游乐场):

var v interface{} = ""
fmt.Println(reflect.ValueOf(v).IsZero())           // true, the empty string "" is zero
fmt.Println(reflect.ValueOf(&v).Elem().IsZero())   // false, the interface itself is not zero

差异是由于ValueOf的参数是interface{}。如果传递一个接口,它将打开其中的动态值。ValueOf的Go文档提醒:

ValueOf返回一个初始化为的新Value,即存储在接口i

中的具体值

使用ValueOf(&v)代替"接口中存储的具体值";将是指向v的指针。然后与Elem()解引用以获得原始值,最后检查IsZero()

大多数情况下,你想要的可能是reflect.ValueOf(&v).Elem().IsZero(),尽管YMMV。

Go 1.18和泛型

对于泛型,您可以通过在var zero T*new(T)上使用==操作符来检查变量是否为零值。类型参数必须是可比较的 (comparable约束或可比较类型的类型集)。

func IsZeroVar[T ~int64 | ~string](v T) bool {
    var zero T
    return v == zero
}
func IsZeroNew[T ~int64 | ~string](v T) bool {
    return v == *new(T)
}

如果类型参数不可比较,则必须返回到反射,如上所示。

下面两个都给出了合理的结果(可能是因为它们是相同的?)

reflect.ValueOf(v) == reflect.Zero(reflect.TypeOf(v)))
reflect.DeepEqual(reflect.ValueOf(v), reflect.Zero(reflect.TypeOf(v)))

。各种整数0口味和未初始化的struct s都是"零"

遗憾的是,空字符串和数组不是。而nil给出一个异常。

相关内容

  • 没有找到相关文章

最新更新