英文:
How to know if a variable of arbitrary type is Zero in Golang?
问题
因为不是所有类型都可以进行比较,例如切片。所以我们不能这样做:
var v ArbitraryType
v == reflect.Zero(reflect.TypeOf(v)).Interface()
英文:
Because not all types are comparable, e.g. a slice. So we can't do this
var v ArbitraryType
v == reflect.Zero(reflect.TypeOf(v)).Interface()
答案1
得分: 8
Go 1.13在reflect
包中引入了Value.IsZero
方法。使用它可以检查零值,示例如下:
if reflect.ValueOf(v).IsZero() {
// v是零值,执行某些操作
}
除了基本类型外,它还适用于Chan、Func、Array、Interface、Map、Ptr、Slice、UnsafePointer和Struct类型。
英文:
Go 1.13 introduced Value.IsZero
method in reflect
package. This is how you can check for zero value using it:
if reflect.ValueOf(v).IsZero() {
// v is zero, do something
}
Apart from basic types, it also works for Chan, Func, Array, Interface, Map, Ptr, Slice, UnsafePointer, and Struct.
答案2
得分: 3
正如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
}
在这里可以看到一个使用示例。
英文:
As Peter Noyes points out, you just need to make sure you're not comparing a type which isn't comparable. Luckily, this is very straightforward with the reflect
package:
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
}
See an example use here.
答案3
得分: 3
反射
这取决于当 v
是一个接口时你想要的行为(对于其他类型来说是一样的):
reflect.ValueOf(v).IsZero()
检查接口中封装的值是否为零reflect.ValueOf(&v).Elem().IsZero()
检查接口变量本身是否为零
演示(playground):
var v interface{} = ""
fmt.Println(reflect.ValueOf(v).IsZero()) // true,空字符串""是零值
fmt.Println(reflect.ValueOf(&v).Elem().IsZero()) // false,接口本身不是零值
这种差异是由于 ValueOf
的参数是 interface{}
。如果传递一个接口,它将解封装其中的动态值。ValueOf
的 Go 文档提醒:
> ValueOf 返回一个新的 Value,其初始化为接口 i 中存储的具体值
通过使用 ValueOf(&v)
而不是 "接口 i 中存储的具体值" 将是指向 v
的指针。然后你使用 Elem()
解引用以获取原始值,最后检查 IsZero()
。
大多数情况下,你可能想要使用 reflect.ValueOf(&v).Elem().IsZero()
,但具体情况可能有所不同。
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
It depends of what behavior you want when v
is an interface (for other types it's the same):
reflect.ValueOf(v).IsZero()
checks whether the value boxed in the interface is zeroreflect.ValueOf(&v).Elem().IsZero()
checks whether the interface variable is zero
Demonstration (playground):
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
The difference is due to the argument of ValueOf
being interface{}
. If you pass an interface, it will unbox the dynamic value boxed in it. The Go docs of ValueOf
remind that:
> ValueOf returns a new Value initialized to the concrete value stored in the interface i
By using ValueOf(&v)
instead "the concrete value stored in the interface i" will be a pointer to v
. Then you dereference with Elem()
to get the original value and finally check IsZero()
.
Most often than not, what you want is probably reflect.ValueOf(&v).Elem().IsZero()
, though YMMV.
Go 1.18 and generics
With generics, you can check if a variable is zero value by using the ==
operator on a var zero T
or *new(T)
. The type parameter must be comparable (comparable
constraint or type set of comparable types).
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)
}
If the type param is not comparable, you must fall back to reflection, as shown above.
答案4
得分: 2
以下两个都给我合理的结果(可能是因为它们是相同的?)
reflect.ValueOf(v) == reflect.Zero(reflect.TypeOf(v)))
reflect.DeepEqual(reflect.ValueOf(v), reflect.Zero(reflect.TypeOf(v)))
例如,各种整数0的形式和未初始化的“struct”都是“zero”。
不幸的是,空字符串和数组不是。而nil
会引发异常。
如果你愿意,你可以对这些进行特殊处理。
英文:
Both of the following give me reasonable results (probably because they're the same?)
reflect.ValueOf(v) == reflect.Zero(reflect.TypeOf(v)))
reflect.DeepEqual(reflect.ValueOf(v), reflect.Zero(reflect.TypeOf(v)))
e.g. various integer 0 flavours and uninitialized struct
s are "zero"
Sadly, empty strings and arrays are not. and nil
gives an exception.
You could special case these if you wanted.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论