Swift: структура Hashable со свойством словаря

У меня есть структура в Swift, которая выглядит так:

internal struct MapKey {
    internal let id: String
    internal let values: [String:String]
}
extension MapKey: Equatable {}
func ==(lhs: MapKey, rhs: MapKey) -> Bool {
    return lhs.id == rhs.id && lhs.values == rhs.values
}

Теперь мне нужно использовать MapKey как ключ в словаре Swift, который требует, чтобы MapKey соответствовал протоколу Hashable.

Какова была бы правильная реализация Hashable для такой структуры?

extension MapKey: Hashable {
    var hashValue: Int {
        return ??? // values does not have a hash function/property.
    }
}

Я занимался некоторыми исследованиями, но не смог определить, какой правильный способ хешировать словарь, поскольку мне нужно иметь возможность генерировать значение хеша для самого свойства values. Любая помощь очень ценится.

Ответ 1

Я думаю, вам нужно просмотреть свою модель данных, если вам нужно использовать целую структуру в качестве словарного ключа. Во всяком случае, здесь один из способов сделать это:

internal struct MapKey: Hashable {
    internal let id: String
    internal let values: [String:String]

    var hashValue: Int {
        get {
            var hashString = self.id + ";"
            for key in values.keys.sort() {
                hashString += key + ";" + values[key]!
            }

            return hashString.hashValue
        }
    }
}

func ==(lhs: MapKey, rhs: MapKey) -> Bool {
    return lhs.id == rhs.id && lhs.values == rhs.values
}

Это предполагает, что у вас нет точки с запятой (;) в id или в клавишах и значениях values. Hasable подразумевает Equatable, поэтому вам не нужно снова объявлять его соответствующим Equatable.

Ответ 2

Так как оба id и значения неизменяемы, оба могут использоваться в качестве основы для equals и hashValue. Однако, если MapKey.id(что несколько подразумевает название) однозначно идентифицирует MapKey (по крайней мере, в контексте одного словаря) то проще и эффективнее использовать MakKey.id в качестве основы для оператора ==, а также hashValue

    internal struct MapKey: Hashable {
        internal let id: String
        internal let values: [String:String]

        var hashValue: Int {
            get { return  self.id.hashValue}
        }
    }

    func ==(lhs: MapKey, rhs: MapKey) -> Bool {
        return lhs.id == rhs.id
    }