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.
    }
}

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

Ответы на вопрос(3)

вам нужно только позволить вашей структуре MapKey соответствовать протоколу Hashable:

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

в случае, если вы хотите использовать класс, вам нужно соответствовать hash (:) func следующим образом:

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

    let id: String = ""
    let values: [String: String] = [:]

    func hash(into hasher: inout Hasher) {
        hasher.combine(id)
        hasher.combine(values)
    }
}
Решение Вопроса

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

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 снова.

 Honey18 нояб. 2016 г., 18:55
Ваш код использует одну и ту же реализацию для хеша и равенства, и это гарантирует конфликт
 Code Different18 нояб. 2016 г., 18:13
@ Меньше, вам не нужно декларировать соответствие Equatable, потому что Hashable уже подразумевает это. Функции == обеспечивают реализацию, требуемую Equatable.
 Honey18 нояб. 2016 г., 17:32
Поправьте меня если я ошибаюсь. Читать этоответ Я думаю тыделать нужно реализовать Equatable отдельноснова
 Martin R23 июн. 2016 г., 22:47
Вам не нужно делать какие-либо предположения относительно точки с запятой (и вставлять такой разделитель не нужно), поскольку хэши не обязательно должны быть уникальными.
 Honey18 нояб. 2016 г., 21:22
Я наконец взломал его и написал свой ответВот Надеюсь, это было бы полезно для других, кто имел такую ​​же путаницу.
 unbekant23 июн. 2016 г., 23:23
Согласился с @MartinR. Спасибо за идею Code, это решит мои текущие потребности, буду благодарен за совет по пересмотру модели данных, учту это.
 Honey18 нояб. 2016 г., 18:48
@CodeDifferent не совсем то, что говорит вам связанный ответдолжен делать? Я имею в виду, что если по какой-либо причине ваше хеш-значение будет таким же, то оно переключится на равную функцию и попробует это. Или дело в другом? Не могли бы вы объяснить?

и значения являются неизменяемыми, их можно использовать как основу для 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
    }
 unbekant23 июн. 2016 г., 23:25
Хорошее наблюдение, Эрик. К сожалению, именно комбинация значений id + делает ключ уникальным в моем случае, хотя идентификатор заставил бы вас думать иначе. Возможно, я не выбрал лучшие имена для моего примера.

Ваш ответ на вопрос