Hashable и hash(into:)
Используйте типы как ключи словаря и элементы множества.
«Hashable и hash(into:)» — бесплатный урок Swift Academy на CoddyKit. Это урок 2 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Swift Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Swift Academy содержит 4 уроков всего.
Что такое хешируемость
Hashable расширяет возможности Equatable и предоставляет хеш-значение. Это необходимо, чтобы использовать тип в качестве элемента Set или ключа Dictionary.
Автоматическое хеширование
Как и для Equatable, для структур и перечислений с хешируемыми элементами соответствие синтезируется автоматически:
struct Point: Hashable {
let x: Int
let y: Int
}
let set: Set<Point> = [Point(x: 0, y: 0), Point(x: 0, y: 0)]
print(set.count) // 1 -- duplicate collapsedИспользование типа в качестве ключа словаря
Хешируемые типы можно использовать как ключи словаря:
struct Coord: Hashable { let r: Int; let c: Int }
var grid: [Coord: String] = [:]
grid[Coord(r: 0, c: 0)] = "start"
print(grid[Coord(r: 0, c: 0)]!) // "start"Контракт хешируемости
Два равных значения (==) MUST выдавать один и тот же хеш. Если Вы настраиваете один из этих механизмов, согласуйте их между собой, иначе множества и словари будут работать неправильно.
Пользовательский hash(into:)
Реализуйте hash(into:), передавая хешеру соответствующие свойства:
struct User: Hashable {
let id: Int
let name: String
func hash(into hasher: inout Hasher) {
hasher.combine(id)
}
static func == (l: User, r: User) -> Bool { l.id == r.id }
}
print(Set([User(id: 1, name: "A"), User(id: 1, name: "B")]).count) // 1Объединение нескольких полей
Передавайте каждое поле, участвующее в проверке равенства:
struct Pair: Hashable {
let a: Int
let b: String
func hash(into hasher: inout Hasher) {
hasher.combine(a)
hasher.combine(b)
}
}
print(Pair(a: 1, b: "x").hashValue == Pair(a: 1, b: "x").hashValue) // trueПочему следует хешировать только поля идентичности
Хешируйте только поля, используемые в ==. Добавление дополнительных изменяемых полей может нарушить правило: из равенства значений должно следовать равенство их хешей:
struct Doc: Hashable {
let id: Int // identity
var title: String // not part of equality
func hash(into hasher: inout Hasher) { hasher.combine(id) }
static func == (l: Doc, r: Doc) -> Bool { l.id == r.id }
}
print(Doc(id: 1, title: "v1") == Doc(id: 1, title: "v2")) // trueХешируемые перечисления
Перечисления автоматически становятся хешируемыми, в том числе с ассоциированными значениями, если сами эти значения поддерживают хеширование:
enum Direction: Hashable { case north, south, east, west }
let visited: Set<Direction> = [.north, .north, .east]
print(visited.count) // 2Удаление дубликатов с помощью множества
Распространённый случай использования: удаление дубликатов за счёт преобразования значений в Set:
let nums = [1, 2, 2, 3, 3, 3]
let unique = Array(Set(nums)).sorted()
print(unique) // [1, 2, 3]Хешер рандомизируется при каждом запуске
Хеш-значения получают начальное значение при каждом запуске программы, поэтому никогда не сохраняйте hashValue на диске и не рассчитывайте на его точное число между запусками:
struct K: Hashable { let v: Int }
let h1 = K(v: 5).hashValue
// h1 is stable within this run only
print(K(v: 5) == K(v: 5)) // true -- equality is what to rely onПодсчёт с помощью словаря
Хешируемые ключи позволяют подсчитывать частоты — это очень распространённый шаблон:
let letters = ["a", "b", "a", "c", "b", "a"]
var counts: [String: Int] = [:]
for l in letters { counts[l, default: 0] += 1 }
print(counts["a"]!) // 3Быстрая проверка
Какое правило должен соблюдать hash(into:) относительно ==?
Итоги
Вы изучили Hashable:
HashableрасширяетEquatableи требуется для ключейSet/Dictionary- Синтезируется для структур и перечислений с хешируемыми элементами
- В пользовательском
hash(into:)объединяйте только поля идентичности, используемые в== - Равные значения должны иметь одинаковые хеши; хеши рандомизируются при каждом запуске
Далее: сопоставимость и сортировка.
Часто задаваемые вопросы
Урок «Hashable и hash(into:)» бесплатный?
Да — полный текст урока «Hashable и hash(into:)» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Swift Academy, подпишись на CoddyKit PRO. Курс Swift Academy содержит 4 уроков всего.
Чему я научусь в уроке «Hashable и hash(into:)»?
Используйте типы как ключи словаря и элементы множества. Ты практикуешь Swift Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Swift Academy?
Предыдущий опыт не требуется. Swift Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 2 из 4.
Сколько времени занимает урок «Hashable и hash(into:)»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Swift Academy?
Да. Каждый урок Swift Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Синтезированный Equatable
- Hashable и hash(into:)
- Comparable и сортировка
- Пользовательская семантика равенства