如何检查泛型类型的值是否为零值?

huangapple go评论72阅读模式
英文:

How to check if the value of a generic type is the zero value?

问题

泛型提案中有一个章节,介绍了如何返回类型参数的零值,但没有提及如何检查参数化类型的值是否为零值。

我能想到的唯一方法是使用reflect.ValueOf(...).IsZero(),是否有其他替代方法?

英文:

The generics proposal has a section on how to return the zero value of a type parameter, but it does not mention how to check if a value of a parametrized type is the zero value.

The only way I can think of is to use reflect.ValueOf(...).IsZero(), is there an alternative?

答案1

得分: 3

使用等号运算符与*new(T)习语一起使用。泛型参数的约束必须是comparable,以支持等号运算符,或者指定一个可比较类型的类型集合:

func IsZero[T comparable](v T) bool {
    return v == *new(T)
}

如果无法将T约束为comparable,则只能使用反射。Zombo建议像这样处理变量:

reflect.ValueOf(&v).Elem().IsZero()

比起简单地使用reflect.ValueOf(v).IsZero(),这种方法更好,因为ValueOf接受一个interface{}参数,如果v恰好是一个接口,你将丢失该信息。我认为在泛型中很少会使用接口实例化函数,但这也值得知道。所以:

func IsZero[T any](v T) bool {
    return reflect.ValueOf(&v).Elem().IsZero()
}

使用类型为T的变量并在比较中使用它也是有效的。它比*new(T)更易读,但需要额外的var声明。操作数仍然必须是可比较的:

func IsZero[T comparable](v T) bool {
    var zero T
    return v == zero
}

如果你担心反射的性能问题,它确实比纯可比较的泛型稍差:

go1.18rc1 test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkGenerics-10      	1000000000	    0.3295 ns/op	 0 B/op	  0 allocs/op
BenchmarkReflection-10    	94129023	    12.26 ns/op	     8 B/op	  1 allocs/op

如果你知道不会使用接口实例化基于反射的函数,你可以简化代码为reflect.ValueOf(v).IsZero(),这会略微提高性能:

go1.18rc1 test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkGenerics-10      	  1000000000	0.3295 ns/op	 0 B/op	  0 allocs/op
BenchmarkReflection-10    	  94129023	    12.26 ns/op	     8 B/op	  1 allocs/op
BenchmarkReflectionNoAddr-10  100000000	    11.41 ns/op	     8 B/op	  0 allocs/op
英文:

Use the equal operator with the *new(T) idiom. The constraint of the generic param must be, or embed, comparable to support the equality operator, or specify a type set of comparable types:

func IsZero[T comparable](v T) bool {
    return v == *new(T)
}

If you can’t constrain T to comparable then you’re left with reflection. Zombo’s suggestion to address the variable like this:

reflect.ValueOf(&v).Elem().IsZero()

is superior to simply reflect.ValueOf(v).IsZero() because ValueOf takes an interface{} argument and if v just happens to be an interface you would loose that information. I don’t think that with generics you will often instantiate a function with an interface but it’s worth knowing. So:

    func IsZero[T any](v T) bool {
        return reflect.ValueOf(&v).Elem().IsZero()
    }

Using a variable of type T and using that in the comparison also works. It is more readable than *new(T), but it requires an additional var declaration. The operands still must be comparable:

func IsZero[T comparable](v T) bool {
    var zero T
    return v == zero
}

If you are concerned about the performance of reflection, it is indeed slightly worse than pure comparable generics:

go1.18rc1 test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkGenerics-10      	1000000000	    0.3295 ns/op	 0 B/op	  0 allocs/op
BenchmarkReflection-10    	94129023	    12.26 ns/op	     8 B/op	  1 allocs/op

If you know you won't instantiate the reflect-based function with an interface, you can simplify the code to reflect.ValueOf(v).IsZero() which gives a minor improvement:

go1.18rc1 test -v -bench=. -benchmem
goos: darwin
goarch: arm64
pkg: example.com
BenchmarkGenerics-10      	  1000000000	0.3295 ns/op	 0 B/op	  0 allocs/op
BenchmarkReflection-10    	  94129023	    12.26 ns/op	     8 B/op	  1 allocs/op
BenchmarkReflectionNoAddr-10  100000000	    11.41 ns/op	     8 B/op	  0 allocs/op

答案2

得分: 2

如果类型是可比较的,那么将值与设置为该类型的零值的变量进行比较。

var zero T
isZero := v == zero

如果类型不可比较,则使用 reflect 包:

isZero := reflect.ValueOf(&v).Elem().IsZero()
英文:

If the type is comparable, then compare the value to a variable set to the zero value of the type.

var zero T
isZero := v == zero

Use the reflect package if the type is not comparable:

isZero := reflect.ValueOf(&v).Elem().IsZero()

huangapple
  • 本文由 发表于 2022年2月20日 00:12:29
  • 转载请务必保留本文链接:https://go.coder-hub.com/71186757.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定