英文:
Go with Generics: type parameter T is not comparable with ==
问题
我正在玩弄Go语言中的泛型,尝试编写一些通用的数组函数。
我遇到的错误是:
invalid operation: val == needle (type parameter T is not comparable with ==)
我可以通过使用反射来解决这个问题:
if reflect.ValueOf(val).Interface() == reflect.ValueOf(needle).Interface()
然而,是否有一个(内部的?)接口用于“可比较”类型,其中定义了==
运算符,我可以使用它来替代any
?
是否真的有不支持使用==
进行比较的类型?
英文:
I am playing around with Go Generics in the playground, trying to write some generic array functions.
https://gotipplay.golang.org/p/vS7f_Vxxy2j
package main
import (
"fmt"
)
func array_has[T any](haystack []T, needle T) bool {
for _, val := range haystack {
if val == needle {
return true
}
}
return false
}
func main() {
arr := []string{"A","B","C"}
fmt.Println(array_has(arr, "T"))
}
The error I am getting is:
> invalid operation: val == needle (type parameter T is not comparable with ==)
I can work around it by using reflect:
if reflect.ValueOf(val).Interface() == reflect.ValueOf(needle).Interface()
Go2 Playground: https://gotipplay.golang.org/p/9ZVZafQ_9JK
However, is there an (internal?) interface for "comparable" types, for which ==
is defined, that I can use instead of any
?
Are there really even types that do not support comparison with ==
?
答案1
得分: 19
比较运算符==
和!=
只能用于确实可比较的参数化类型。参考Go规范:比较运算符:
> 切片、映射和函数值是不可比较的。
通过使用类型约束any
,你可以允许任何类型,包括那些不可比较的类型(切片、映射和函数),因此会产生你看到的编译器错误。
相反,你可以使用预声明的约束comparable
,将类型参数限制为定义了==
和!=
的类型,除了接口。
因此,编写函数签名的正确方式是:
func array_has[T comparable](haystack []T, needle T) bool
除了comparable
,你还可以使用嵌入comparable
的接口约束,或者更严格的约束,只包括可比较的类型,例如:
func array_has[T ~string](haystack []T, needle T) bool
<hr>
注意1:受comparable
约束的类型允许使用==
和!=
,但不允许使用顺序运算符<
、>
、<=
和>=
。详情请参考https://stackoverflow.com/questions/70562572/in-go-generics-why-cant-i-use-comparable-constraint-with-order-operators/70562597#70562597
<hr>
注意2:comparable
是一个预声明的标识符,而不是关键字。区别在于你可以在较窄的作用域中重新声明它并遮蔽内置的标识符。为了明确起见,这个程序可以编译。这是一个需要了解的好消息,因为这是泛型实现与早期Go版本向后兼容的原因之一,即具有变量名为"comparable"的旧程序仍然可以编译。
<hr>
约束comparable
也是你在映射键上声明类型参数所需的。映射键还必须支持==
和!=
运算符。
func useKeys[K comparable, V any](m map[K]V) {
// 使用映射键
}
英文:
Comparison operators ==
and !=
can be used only on parametrized types that are indeed comparable. Referring to the Go specs: Comparison Operators:
> Slice, map, and function values are not comparable.
By using the type constraint any
, you are allowing literally any type, including those that are not comparable (slices, maps and functions), thus producing the compiler error you saw.
Instead you can use the predeclared constraint comparable
that restricts the type parameter to those that define ==
and !=
, except interfaces.
So the correct way to write your function signature is
func array_has[T comparable](haystack []T, needle T) bool
Instead of comparable
you can also use interface constraints that embed comparable
, or stricter constraints that include only types that are comparable, e.g.:
func array_has[T ~string](haystack []T, needle T) bool
<hr>
Note 1: types constrained by comparable
allow ==
and !=
but not order operators <
, >
, <=
and >=
. For details, see https://stackoverflow.com/questions/70562572/in-go-generics-why-cant-i-use-comparable-constraint-with-order-operators/70562597#70562597
<hr>
Note 2: comparable
is a predeclared identifier, not a keyword. The difference is that you can redeclare it in a narrower scope and shadow the built-in one. To be clear this program compiles. This is good to know, as it's one of the reasons why the generics implementation is backwards compatible with earlier Go versions, i.e. old programs with variables named "comparable" will still compile.
<hr>
The constraint comparable
is also what you need to declare type parameters on map keys. Map keys must also support ==
and !=
operators.
func useKeys[K comparable, V any](m map[K]V) {
// use map keys
}
答案2
得分: 8
如您所见,根据提案,"适用于任何类型的操作",直接比较any
类型的值是不可能的。然而,这并不是唯一可能的泛型约束。
这就是comparable
的用途,它允许使用比较操作。您可以将any
替换为它,您的函数将正常工作:
func array_has[T comparable](haystack []T, needle T) bool {
for _, val := range haystack {
if val == needle {
return true
}
}
return false
}
这在playground上可以运行。
我不确定是否存在无法使用==
进行比较的类型,所以这似乎有点奇怪。
英文:
As you can see from the proposal, section "Operations permitted for any type", it is not directly possible to compare values of the any
type. However, it's not the only possible generic constraint.
This is where comparable
comes in, it allows using comparisons. You can replace the any
with it and your function will work:
func array_has[T comparable](haystack []T, needle T) bool {
for _, val := range haystack {
if val == needle {
return true
}
}
return false
}
This works on the playground.
I'm not sure if there are types that are not comparable using ==
, so that seems a bit weird.
答案3
得分: 3
是的,有很多。其中一个显著的例子是映射和切片,还有函数等。
如果有疑问,请参考规范。
英文:
> Are there really even types that do not support comparison with == ?
Yes, a lot. Maps and slices being a prominent example, functions an other.
When in doubt: Consult the spec.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论