【发布时间】:2022-12-03 03:48:22
【问题描述】:
我曾尝试在 Go 中使用泛型,但当我们使用 any 或 comparable 作为类型参数时,我真的不明白。有人可以帮助理解这些吗?
【问题讨论】:
标签: go generics comparable any
我曾尝试在 Go 中使用泛型,但当我们使用 any 或 comparable 作为类型参数时,我真的不明白。有人可以帮助理解这些吗?
【问题讨论】:
标签: go generics comparable any
这取决于您要使用什么/如何使用参数类型的值。约束限制了您可以对这些类型的值执行的操作。
any 是interface{} 的别名,它允许任何类型。如果一个参数可以是任何类型,那基本上不允许你用它做任何事情,因为你不能保证它会是什么。
comparable 约束只允许可比较的类型,也就是说,== 和!= 运算符允许在它们的值上使用。如果您想将类型用作映射中的键(映射要求键类型具有可比性),或者如果您想在切片中查找元素,并且想使用 == 运算符来将元素与某物进行比较。
例如,让我们编写一个通用的 map-get 函数:
func get[K comparable, V any](m map[K]V, key K) V {
return m[key]
}
K键类型必须是comparable,否则不能作为某些映射的键类型(示例中的m[K]V)。另一方面,V 不应该被限制,值类型可以是任何东西,我们没有对它做任何事情(只是返回V 类型的值),所以在这里使用any 是最好的选择。
另一个例子,一个 slice-find 函数:
func find[V comparable](what V, s []V) int {
for i, v := range s {
if v == what {
return i
}
}
return -1
}
find() 返回 what 在切片 s 中第一次出现的索引,如果它不在切片中,则返回 -1。这里的类型参数V必须是comparable,否则不能写成v == what,使用V any会编译出错。约束 comparable 确保此 find() 函数只能使用定义并允许 == 运算符的类型实例化(并使用值调用)。
【讨论】:
comparable 适合map。我会试试看那里会发生什么。顺便说一句,感谢@icza 的解释。
== 和/或 != 运算符的任何内容。
comparable 和 any 之间的区别将随着 Go 1.20(2023 年第一季度)和(接受)提案“56548: spec: allow basic interface types to instantiate comparable type parameters”而改变。
any 将实现可比约束(Go 1.20 之前没有)。
规范“Instantiations”部分将说明:
替换后,每个类型参数必须满足相应类型参数的约束(如有必要,实例化)。否则实例化失败。
“满足”是:
类型
T满足约束接口C如果
T实现C;或者C可以写成interface{ comparable; E }的形式,其中E是基本接口,T是可比的,实现了E。例子:
目前,
any没有实现 comparable 约束。根据提议的更改,
any将被允许作为可比较的类型参数:comparable可以写成interface{ comparable; E },因此新规则适用,any是规范可比较的并实现E(其中 @987654344 @ 在这种情况下是空接口)。目前,类型参数列表中的类型参数
P[P interface{ comparable; fmt.Stringer }]不能用类型 S 实例化
type S struct { data any } func (S) String() string因为
S不具有严格的可比性。
根据提议的更改,S必须仅可进行规范比较(确实如此)并实现fmt.Stringer(确实如此)。(“spec-comparable”适用于comparable operands 的类型)
(与“严格可比较”相反,它适用于comparable中的类型,即定义了==和!=的一组(非接口)类型,并且保证这些操作不会恐慌)开始实施:
【讨论】: