【问题标题】:Go map with user-defined key with user-defined equality?使用用户定义的键映射用户定义的相等性?
【发布时间】:2015-06-22 02:37:03
【问题描述】:

假设我在 Go 中有一个结构类型,我想将其用作映射中的键,但我想使用 Go 的内置相等操作。构建此类地图的最佳方法是什么?

举个具体的例子,这是我的键类型和相等操作:

type Key struct {
    a *int
}

func Equal(x Key, y Key) bool {
    return *x.a == *y.a
}

如何构建使用Equal 进行键比较的地图?

【问题讨论】:

  • 但是我如何声明该地图应该使用该方法?更糟糕的是,在我的真实代码中,字段 a 是 int 的一个 slice,据我所知,silces 没有内置的相等操作。
  • 是的,在常见问题解答golang.org/doc/faq 中有一个问题是“为什么地图不允许切片作为键”,答案是没有内置的相等运算符。我在回答中提出了我认为最合理的解决方案。

标签: go


【解决方案1】:

这在 Go 中是不可能的。没有可以覆盖的运算符重载或“平等”方法(由于没有从您的示例让我想起的.NET 等公共基类继承)。如果您有兴趣,这个答案有更多关于平等比较的信息; Is it possible to define equality for named types/structs?

正如 cmets 中提到的,如果你想做这样的工作,我建议使用对象上的属性作为键。您可以根据您设置该属性的值的方式来定义相等性(例如,如果您正在寻找成员相等性,它可以是对象字节的校验和或其他东西)。

【讨论】:

    【解决方案2】:

    Go 有 strict comparable semantics for values used as map keys。因此,您无法像在许多其他语言中那样为映射键定义自己的哈希码和相等函数。

    但是,请考虑以下解决方法。不要将结构实例直接用作键,而是使用结构的派生属性,该属性本质上可用作键并具有您想要的相等语义。通常很容易将整数或字符串值导出为哈希码,用作实例的标识。

    例如:

    type Key struct {
      a *int
    }
    
    func (k *Key) HashKey() int {
      return *(*k).a
    }
    
    k1, k2 := Key{intPtr(1)}, Key{intPtr(2)}
    m := map[int]string{}
    m[k1.HashKey()] = "one"
    m[k2.HashKey()] = "two"
    // m = map[int]string{1:"one", 2:"two"}
    m[k1.HashKey()] // => "one"
    

    当然,不变性是这种方法的一个关键问题。在上面的示例中,如果您修改字段a,则该实例不能再用作哈希键,因为它的标识已更改。

    【讨论】:

    • 谢谢。在我的真实代码中,我将切片作为键。我想我必须对 128 位值使用非常高质量的散列,或者将它们“散列”到字符串。
    • @ArchD.Robison:当然,内置的crypto/md5 package 可能对此有所帮助,甚至是通过fmt.Sprintf("%v",slc) 的切片的简单字符串表示。
    猜你喜欢
    • 2019-03-25
    • 1970-01-01
    • 1970-01-01
    • 2012-04-07
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    • 2013-06-03
    • 2012-02-08
    相关资源
    最近更新 更多