Исключение свойства из вычисления значения ha sh - PullRequest
3 голосов
/ 10 июля 2020

Есть ли способ использовать hash(into:) для вычисления хэш-значения структуры / класса, не используя при этом определенные свойства?

т.е.

struct CacheItem: Codable, Hashable {
    let val1: Int
    let val2: Int
    let date: Date = Date()

    func hash(into hasher: inout Hasher) {
        hasher.combine(val1) // leave out date for computing hash value
        hasher.combine(val2)
    }
}

Я надеялся, что это будет работа:

let cache = Set<CacheItem>()
let item1 = CacheItem(val1: 0, val2: 0)
let item2 = CacheItem(val1: 0, val2: 0)

cache.insert(item1)
assert(cache.contains(item2))

Однако не сработало.

1 Ответ

5 голосов
/ 10 июля 2020

A Set - это набор уникальных объектов, и равенство основывается на сравнении с ==. Равные объекты должны иметь одинаковое значение ha sh, но не наоборот: разные объекты могут иметь одно и то же значение ha sh. (Простой пример: существует 2 64 возможных значений ha sh, но бесконечно много строк. Таким образом, обязательно существуют разные строки с одинаковым значением ha sh.)

Hashable коллекции (например, Set и Dictionary) используют значение ha sh в своей реализации (например, для помещения разных объектов в разные «корзины»), но они никогда не используют значение ha sh отдельно для определения равенства.

Реализация по умолчанию == сравнивает все (сохраненные) свойства на равенство. Следовательно, в вашем случае, если item1 и item2 имеют одинаковые val1 и val2, но разные date, то это разные объекты, даже если они имеют одинаковое значение ha sh.

Если вы хотите, чтобы объекты с одинаковыми val1 и val2, но разными date считались равными, вы должны реализовать == самостоятельно:

struct CacheItem: Codable, Hashable {
    // ...
    
    static func ==(lhs: CacheItem, rhs: CacheItem) -> Bool {
        return lhs.val1 == rhs.val1 && lhs.val2 == rhs.val2
    }
}

Тогда

var cache = Set<CacheItem>()
let item1 = CacheItem(val1: 0, val2: 0)
let item2 = CacheItem(val1: 0, val2: 0)

cache.insert(item1)
print(cache.contains(item2))

всегда будет печатать true.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...