Одинаковые объекты должны иметь одинаковое значение хеш-функции, но не наоборот: отдельные объекты могут иметь одинаковое значение хеш-функции.Проверка на равенство должна выполняться с ==
и , никогда не полагаться только на одно хеш-значение.
В этом конкретном случае обратите внимание, что существует более 2 64 Decimal
значений, так что на самом деле было бы невозможно присвоить разные значения хеш-функции всем им.(Аналогично для строк, массивов, словарей, ...).
Если у вас есть пользовательская структура, содержащая Decimal
(и, возможно, другие) свойства, то реализация протокола Equatable
и Hashable
должнавыглядит следующим образом:
struct Foo: Hashable {
let value: Decimal
let otherValue: Int
static func == (lhs: Foo, rhs: Foo) -> Bool {
return lhs.value == rhs.value && lhs.otherValue == rhs.otherValue
}
func hash(into hasher: inout Hasher) {
hasher.combine(value)
hasher.combine(otherValue)
}
}
Обратите внимание, что если все сохраненные свойства равны Hashable
, то компилятор может автоматически синтезировать эти методы, и этого достаточно для объявления соответствие:
struct Foo: Hashable {
let value: Decimal
let otherValue: Int
}
Примечание: Я предполагаю, что поведение наследуется от типа Foundation NSDecimalNumber
.С бета-версией Xcode 11 (Swift 5.1) x
и -x
имеют различные значения хеш-функции, такие как Decimal
, но такое же значение хеш-функции, как NSDecimalNumber
:
let d1: Decimal = 123
let d2: Decimal = -123
print(d1.hashValue) // 1891002061093723710
print(d2.hashValue) // -6669334682005615919
print(NSDecimalNumber(decimal: d1).hashValue) // 326495598603
print(NSDecimalNumber(decimal: d2).hashValue) // 326495598603
(Ваши значения могут отличаться, поскольку хэшзначения рандомизированы, начиная со Swift 4.2.) Но вышеизложенное все еще применимо: всегда могут быть коллизии, и нельзя полагаться на разные значения, имеющие разные хэши.