使用泛型:类型参数 T 不能与 == 进行比较
Go with Generics: type parameter T is not comparable with ==
我正在操场上玩 Go 泛型,尝试编写一些泛型数组函数。
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"))
}
我得到的错误是:
invalid operation: val == needle (type parameter T is not comparable with ==)
我可以使用 reflect 解决这个问题:
if reflect.ValueOf(val).Interface() == reflect.ValueOf(needle).Interface()
Go2 游乐场:https://gotipplay.golang.org/p/9ZVZafQ_9JK
但是,是否有针对定义了 ==
的“可比较”类型的(内部?)接口,我可以使用它来代替 any
?
真的有不支持与==
比较的类型吗?
从proposal, section "Operations permitted for any type"可以看出,无法直接比较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。
我不确定是否有不能使用==
进行比较的类型,所以这看起来有点奇怪。
比较运算符 ==
和 !=
只能用于确实可比较的参数化类型。参考 Go specs: Comparison Operators:
Slice, map, and function values are not comparable.
通过使用类型约束 any
,您实际上允许任何类型,包括那些不可比较的类型(切片、映射和函数),从而产生您看到的编译器错误。
您可以使用预声明约束 comparable
将类型参数限制为定义 ==
和 !=
、.
的类型参数
所以函数签名的正确写法是
func array_has[T comparable](haystack []T, needle T) bool
您还可以使用嵌入 comparable
的接口约束或仅包含可比较类型的更严格的约束,而不是 comparable
,例如:
func array_has[T ~string](haystack []T, needle T) bool
注 1:受 comparable
约束的类型允许 ==
和 !=
但不允许顺序运算符 <
、>
、<=
和>=
。有关详细信息,请参阅
注2:comparable
是一个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编译。很高兴知道这一点,因为这是泛型实现向后兼容早期 Go 版本的原因之一,即具有名为“comparable”的变量的旧程序仍然可以编译。
约束comparable
也是您在映射键上声明类型参数所需要的。映射键还必须支持 ==
和 !=
运算符。
func useKeys[K comparable, V any](m map[K]V) {
// use map keys
}
Are there really even types that do not support comparison with == ?
是的,很多。地图和切片是一个突出的例子,作用是另一个。
如有疑问:请参阅规范。
我正在操场上玩 Go 泛型,尝试编写一些泛型数组函数。
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"))
}
我得到的错误是:
invalid operation: val == needle (type parameter T is not comparable with ==)
我可以使用 reflect 解决这个问题:
if reflect.ValueOf(val).Interface() == reflect.ValueOf(needle).Interface()
Go2 游乐场:https://gotipplay.golang.org/p/9ZVZafQ_9JK
但是,是否有针对定义了 ==
的“可比较”类型的(内部?)接口,我可以使用它来代替 any
?
真的有不支持与==
比较的类型吗?
从proposal, section "Operations permitted for any type"可以看出,无法直接比较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。
我不确定是否有不能使用==
进行比较的类型,所以这看起来有点奇怪。
比较运算符 ==
和 !=
只能用于确实可比较的参数化类型。参考 Go specs: Comparison Operators:
Slice, map, and function values are not comparable.
通过使用类型约束 any
,您实际上允许任何类型,包括那些不可比较的类型(切片、映射和函数),从而产生您看到的编译器错误。
您可以使用预声明约束 comparable
将类型参数限制为定义 ==
和 !=
、
所以函数签名的正确写法是
func array_has[T comparable](haystack []T, needle T) bool
您还可以使用嵌入 comparable
的接口约束或仅包含可比较类型的更严格的约束,而不是 comparable
,例如:
func array_has[T ~string](haystack []T, needle T) bool
注 1:受 comparable
约束的类型允许 ==
和 !=
但不允许顺序运算符 <
、>
、<=
和>=
。有关详细信息,请参阅
注2:comparable
是一个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编译。很高兴知道这一点,因为这是泛型实现向后兼容早期 Go 版本的原因之一,即具有名为“comparable”的变量的旧程序仍然可以编译。
约束comparable
也是您在映射键上声明类型参数所需要的。映射键还必须支持 ==
和 !=
运算符。
func useKeys[K comparable, V any](m map[K]V) {
// use map keys
}
Are there really even types that do not support comparison with == ?
是的,很多。地图和切片是一个突出的例子,作用是另一个。
如有疑问:请参阅规范。