使用泛型:运算符==未为T定义
我在操场上玩 Go 泛型,试图编写一些通用数组函数。
https://go2goplay.golang.org/p/PFb1jhy1fML
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"))
}
我得到的错误是:
type checking failed for main
prog.go2:9:6: cannot compare val == needle (operator == not defined for T)
我可以通过使用反射来解决它:
if reflect.ValueOf(val).Interface() == reflect.ValueOf(needle).Interface()
Go2 游乐场:https ://go2goplay.golang.org/p/9ZVZafQ_9JK
但是,是否有一个(内部?)“可比较”类型的接口==,为此我可以使用它来代替any?
真的有甚至不支持与 比较的类型==吗?
回答
比较运算符==和!=只能用于确实可比较的参数化类型。
这些在Go 规范中明确定义:比较运算符。特别是:
切片、映射和函数值不可比较。
通过使用类型约束any,您实际上允许任何类型,包括切片、映射和函数。由于这些类型首先不可比较,因此 Go2 编译器会抱怨您提到的错误:
无法比较 val == 针(运算符 == 未为 T 定义)
当前的实现确实提供了一个预先声明的标识符 comparable,将类型参数限制为那些确实定义了==和 的!=。
所以写函数签名的正确方法是
func array_has[T comparable](haystack []T, needle T) bool
为清楚起见,请注意这comparable是预先声明的 identifier,而不是关键字。不同之处在于您可以在更窄的范围内重新声明它并隐藏内置的范围。需要明确的是,以下程序确实可以编译:
package main
func main() {
comparable := 1
fmt.Println(comparable)
}
我认为您通常不需要重新声明标识符,但很高兴知道,因为这是泛型实现向后兼容早期 Go 版本的原因之一,即具有名为“comparable”的变量的旧程序仍将编译.
请记住,comparable正在讨论标识符和类似的内置便利类型。假设这个提议不会改变太多是有点安全的,但是最终的类型参数实现可能会以一些额外的结构结束,用于限制可比较的类型,例如专用包中的导出接口constraints.Comparable。请务必在几个月后回来查看。