Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Go map with user-defined key with user-defined equality?

Tags:

Suppose I have a struct type in Go that I want to use as a key in a map, but I don't want to use Go's builtin equality operation. What's the best way to build such a map?

For a concrete example, here is my key type and equality operation:

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

How can I build a map that uses Equal for key comparison?

like image 258
Arch D. Robison Avatar asked Apr 15 '15 22:04

Arch D. Robison


People also ask

Can we use any user defined data type as a key in map in C++?

We can use any of the data types as the data type of the key of the map. Even a user-defined data type can be used as key data type.

Are Golang map Keys ordered?

As a Golang map is an unordered collection, it does not preserve the order of keys.

How do you check if a key is in a map go?

To check if specific key is present in a given map in Go programming, access the value for the key in map using map[key] expression. This expression returns the value if present, and a boolean value representing if the key is present or not.

What can be a key in Golang map?

In the maps, a key must be unique and always in the type which is comparable using == operator or the type which support != operator. So, most of the built-in type can be used as a key like an int, float64, rune, string, comparable array and structure, pointer, etc.


2 Answers

Go has strict comparable semantics for values used as map keys. As such, you cannot define your own hash code and equality functions for map keys as you can in many other languages.

However, consider the following workaround. Instead of using the struct instances directly as a keys, use a derived attribute of the struct which is intrinsically usable as a key and has the equality semantics you desire. Often it is simple to derive an integer or string value as a hash code which serves as the identity for an instance.

For example:

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" 

Of course, immutability is a critical concern with this approach. In the example above, if you modify the field a then the instance can no longer be used as a hash key because its identity has changed.

like image 180
maerics Avatar answered Nov 05 '22 13:11

maerics


This is not possible in Go. There is no operator overloading or 'Equality' method you can override (due to not inheriting from a common base class like in .NET which your example reminds me of). This answer has more information on equality comparisons if you're interested; Is it possible to define equality for named types/structs?

As mentioned in the comments if you want to make something like this work I would recommend using a property on the object as a key. You can define equality based on how you set the value of that property (like it could be a checksum of the objects bytes or something if you're looking for memberwise equality).

like image 43
evanmcdonnal Avatar answered Nov 05 '22 13:11

evanmcdonnal