Может ли в Swift словаре ключом быть любая структура?
Что проверяют
Знаете ли вы требование Dictionary к ключу и понимаете ли, что компилятор делает за вас, а что нет. Интервьюеру важен контракт между == и хэшем. Следом обычно спрашивают, как написать Hashable вручную и чем опасен изменяемый ключ-класс.
Как отвечать
Не любая. Ключом может быть только тип, соответствующий Hashable, а он наследует Equatable. Для структуры это выглядит так:
- автоматический синтез: достаточно написать
struct Point: Hashable, и если все хранимые свойства самиHashable, компилятор сгенерирует==иhash(into:). Работает с Swift 4.1, но соответствие нужно объявить явно; - ручная реализация: если в структуре есть замыкание или свойство неподходящего типа, синтез не сработает. Тогда пишете
==иhash(into:)сами и передаёте вhasher.combine(_:)только поля, которые определяют идентичность; - дженерики:
struct Box<T>становится ключом через условное соответствиеextension Box: Hashable where T: Hashable; - разнородные ключи: для ключей разных типов в одном словаре есть
AnyHashable.
Главный контракт: если a == b, их хэши обязаны совпадать. Обратное не требуется, коллизии хэшей словарь разрешает сам. Нарушили контракт, например сравниваете по id, а хэшируете ещё и name, и равные ключи попадают в разные корзины: поиск перестаёт находить уже записанное значение.
Полезно сказать про семантику значений: структура-ключ копируется в словарь, поэтому изменение исходной переменной ключ не трогает. С классом иначе: поменяли поле, участвующее в хэше, у объекта, который уже лежит ключом, и словарь его больше не найдёт.
Где спотыкаются
Реализуют устаревшее требование hashValue вместо hash(into:). Компилятор выдаст предупреждение, а самодельная формула хэша обычно хуже встроенного Hasher.
Сохраняют hashValue в базу или на диск и сравнивают после перезапуска. Hasher использует случайное зерно на каждый запуск процесса, поэтому значения между запусками разные.
Делают ключом структуру со всеми полями, включая часто меняющиеся, например дату обновления. Одна и та же сущность после правки становится другим ключом, и в словаре появляются дубли.