Ответ
Основное и обязательное требование — тип ключа должен соответствовать протоколу Hashable.
Почему Hashable?
Dictionary в Swift реализован как хеш-таблица. Для быстрого доступа (в среднем O(1) для вставки, поиска и удаления) необходимо:
- Вычислить хеш-значение ключа для определения "корзины" (bucket), где будет храниться пара ключ-значение.
- Сравнить ключи на равенство (протокол
Hashableнаследуется отEquatable), чтобы разрешать коллизии хешей.
Пример:
// User должен быть Hashable, чтобы быть ключом
struct User: Hashable {
let id: Int // Уникальный идентификатор — хороший кандидат для хеширования
let name: String
}
var scores: [User: Int] = [:] // Dictionary с User в качестве ключа
let alice = User(id: 1, name: "Alice")
scores[alice] = 95 // Успешно, так как User соответствует Hashable
// Попытка использовать не-Hashable тип приведет к ошибке компиляции:
// struct Point { let x, y: Double }
// var dict = [Point: String]() // Ошибка: Type 'Point' does not conform to protocol 'Hashable'
Важные детали:
- Все базовые типы Swift (
String,Int,Double,Boolи т.д.) уже соответствуютHashable. - Для кастомных типов можно получить соответствие
Hashableавтоматически, если все его свойства такжеHashable(как в примере сUserвыше). В противном случае потребуется ручная реализация методовhash(into:)и==. - Уникальность: Если добавляется элемент с ключом, который уже существует в словаре, его значение перезаписывается.
- Иммутабельность: Хеш-значение ключа не должно меняться за время его жизни в словаре. Использование мутирующих объектов в качестве ключа — антипаттерн.