【问题标题】:What is the difference between comparable and any?comparable 和 any 有什么区别?
【发布时间】:2022-12-03 03:48:22
【问题描述】:

我曾尝试在 Go 中使用泛型,但当我们使用 anycomparable 作为类型参数时,我真的不明白。有人可以帮助理解这些吗?

【问题讨论】:

    标签: go generics comparable any


    【解决方案1】:

    这取决于您要使用什么/如何使用参数类型的值。约束限制了您可以对这些类型的值执行的操作。

    anyinterface{} 的别名,它允许任何类型。如果一个参数可以是任何类型,那基本上不允许你用它做任何事情,因为你不能保证它会是什么。

    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 的解释。
    • @Teguh 是的,它适用于地图键,也适用于必须使用 == 和/或 != 运算符的任何内容。
    【解决方案2】:

    comparableany 之间的区别将随着 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 中的类型,即定义了==!= 的一组(非接口)类型,并且保证这些操作不会恐慌)

    开始实施:

    • CL 453979:“cmd/compile:默认启用新的可比语义”
    • CL 453978:“go/typestypes2:将新的可比语义设为默认值”

    【讨论】:

    • 这将改变——什么,会改变?老实说,我认为这个答案不应该贴在这个问题下; icza 的回答甚至没有提到严格可比的限制。而且我认为它不应该这么早发布,因为 Go 规范尚未修改。从今天开始,您引用的是非规范性参考文献。
    猜你喜欢
    • 2017-10-19
    • 2019-06-07
    • 2015-07-12
    • 2019-11-19
    • 1970-01-01
    • 2020-05-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多