9

因为并非所有类型都具有可比性,例如切片。所以我们不能这样做

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

4 回答 4

4

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

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

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

于 2020-05-18T19:17:23.283 回答
2

正如 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
}

在此处查看使用示例。

于 2015-10-14T04:11:08.160 回答
2

以下两项都给了我合理的结果(可能是因为它们相同?)

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

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

例如,各种整数 0 风格和未初始化struct的 s 是“零”

可悲的是,空字符串和数组不是。并nil给出一个例外。
如果你愿意,你可以对这些进行特殊处理。

于 2015-10-14T04:11:08.787 回答
0

反映

这取决于你想要什么行为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{}。如果您传递一个接口,它将取消装箱其中装箱的动态值。Go 文档ValueOf提醒:

ValueOf 返回一个新的 Value,初始化为存储在接口 i 中的具体值

通过使用ValueOf(&v)“存储在接口 i 中的具体值”将成为指向v. 然后你取消引用Elem()以获取原始值,最后检查IsZero().

通常情况下,您想要的可能reflect.ValueOf(&v).Elem().IsZero()是 YMMV。

Go 1.18 和泛型

==使用泛型,您可以通过在 avar 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)
}

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

于 2022-02-20T20:15:34.430 回答