2015-04-15 40 views
6

假设我在Go中有一个结构类型,我想用它作为地图中的一个键,但我不想想要使用Go的内置平等操作。建立这样的地图的最佳方式是什么?使用用户定义的键与用户定义的键相匹配吗?

对于一个具体的例子,这里是我的钥匙型和平等操作:

type Key struct { 
    a *int 
} 

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

如何建立一个使用Equal键比较地图吗?

+0

但我将如何声明地图应该使用该方法?更糟糕的是,在我的真实代码中,字段a是int的一部分,据我所知,silces没有内置的相等操作。 –

+0

在常见问题https://golang.org/doc/faq中有一个问题,'为什么地图不允许切片作为关键字',答案是没有内置的相等运算符。我在我的答案中提出了我认为是最合理的解决方案。 – evanmcdonnal

回答

2

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

正如在评论中提到的,如果你想做出类似这样的工作,我会建议使用对象的属性作为关键。您可以根据您设置该属性值的方式来定义相等性(例如,如果您要查找成员平等,它可能是对象字节的校验和或某些内容)。

6

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,则实例不能再用作散列键,因为其标识已更改。

+0

谢谢。在我的真实代码中,我有切片作为键。我想我必须使用128位值的高质量哈希,或者将它们“哈希”到字符串。 –

+0

@ ArchD.Robison:当然,内建的['crypto/md5'包](http://golang.org/pkg/crypto/md5/)可能对此有所帮助,或者甚至可以通过切片的简单字符串表示['fmt.Sprintf( “%v”,SLC)'](http://golang.org/pkg/fmt/#Sprintf)。 – maerics