使用泛型:类型参数 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 == ?

是的,很多。地图和切片是一个突出的例子,作用是另一个。

如有疑问:请参阅规范。