Перейти к карте с определяемым пользователем ключом с определяемым пользователем равенством?
Предположим, что у меня есть тип структуры в Go, который я хочу использовать в качестве ключа на карте, но я не хочу использовать операцию Go, встроенную в равенство. Какой лучший способ построить такую карту?
Для конкретного примера, вот мой тип ключа и операция равенства:
type Key struct {
a *int
}
func Equal(x Key, y Key) bool {
return *x.a == *y.a
}
Как создать карту, использующую Equal
для сравнения ключей?
Ответы
Ответ 1
Go имеет строго сопоставимую семантику для значений, используемых в качестве ключей карты. Таким образом, вы не можете определить свой собственный хэш-код и функции равенства для ключей карты, как это можно сделать во многих других языках.
Однако рассмотрим следующий обходной путь. Вместо того чтобы использовать экземпляры структуры непосредственно в качестве ключей, используйте производный атрибут структуры, который по своей природе может использоваться в качестве ключа и имеет желаемую семантику равенства. Часто просто получить целое или строковое значение в качестве хеш-кода, который служит идентификатором для экземпляра.
Например:
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
экземпляр больше не будет использоваться в качестве хеш-ключа, поскольку его идентификатор изменился.
Ответ 2
Это невозможно в Go. Нет перегрузки операторов или метода "Равенство", которые вы можете переопределить (из-за отсутствия наследования от общего базового класса, как в .NET, о котором мне напоминает ваш пример). Этот ответ содержит больше информации о сравнениях на равенство, если вам интересно; Можно ли определить равенство для именованных типов/структур?
Как уже упоминалось в комментариях, если вы хотите сделать что-то вроде этой работы, я бы рекомендовал использовать свойство объекта в качестве ключа. Вы можете определить равенство, основываясь на том, как вы устанавливаете значение этого свойства (например, это может быть контрольная сумма байтов объектов или что-то еще, если вы ищете членное равенство).