泛型提案中有一节介绍如何返回类型参数的零值,但没有提到如何检查参数化类型的值是否为零值。
我能想到的唯一方法是使用reflect.ValueOf(...).IsZero(),还有其他选择吗?
将等于运算符与*new(T)习语一起使用。通用参数的约束必须是或嵌入的,comparable以支持相等运算符,或指定可比较类型的类型集:
func IsZero[T comparable](v T) bool {\n return v == *new(T)\n}\nRun Code Online (Sandbox Code Playgroud)\n如果你能\xe2\x80\x99t 约束T,comparable那么你\xe2\x80\x99 就会留下反射。Zombo\xe2\x80\x99s 建议像这样寻址变量:
reflect.ValueOf(&v).Elem().IsZero()\nRun Code Online (Sandbox Code Playgroud)\n优于简单地reflect.ValueOf(v).IsZero()因为ValueOf需要一个interface{}参数,如果v恰好是一个接口,您就会丢失该信息。我不认为使用泛型你会经常用接口实例化一个函数,但它值得了解。所以:
func IsZero[T any](v T) bool {\n return reflect.ValueOf(&v).Elem().IsZero()\n }\nRun Code Online (Sandbox Code Playgroud)\n使用类型变量T并在比较中使用该变量也是可行的。它比 更具可读性*new(T),但需要额外的var声明。操作数仍然必须是可比较的:
func IsZero[T comparable](v T) bool {\n var zero T\n return v == zero\n}\nRun Code Online (Sandbox Code Playgroud)\n如果你关心反射的性能,它确实比纯粹的可比泛型稍差:
\ngo1.18rc1 test -v -bench=. -benchmem\ngoos: darwin\ngoarch: arm64\npkg: example.com\nBenchmarkGenerics-10 1000000000 0.3295 ns/op 0 B/op 0 allocs/op\nBenchmarkReflection-10 94129023 12.26 ns/op 8 B/op 1 allocs/op\nRun Code Online (Sandbox Code Playgroud)\n如果您知道不会使用接口实例化基于反射的函数,则可以简化代码,从而reflect.ValueOf(v).IsZero()进行微小的改进:
go1.18rc1 test -v -bench=. -benchmem\ngoos: darwin\ngoarch: arm64\npkg: example.com\nBenchmarkGenerics-10 1000000000 0.3295 ns/op 0 B/op 0 allocs/op\nBenchmarkReflection-10 94129023 12.26 ns/op 8 B/op 1 allocs/op\nBenchmarkReflectionNoAddr-10 100000000 11.41 ns/op 8 B/op 0 allocs/op\nRun Code Online (Sandbox Code Playgroud)\n