Какое основное требование к ключу при добавлении элемента в Dictionary в Swift?

«Какое основное требование к ключу при добавлении элемента в Dictionary в Swift?» — вопрос из категории Swift Core, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Основное и обязательное требование — тип ключа должен соответствовать протоколу Hashable.

Почему Hashable? Dictionary в Swift реализован как хеш-таблица. Для быстрого доступа (в среднем O(1) для вставки, поиска и удаления) необходимо:

  1. Вычислить хеш-значение ключа для определения "корзины" (bucket), где будет храниться пара ключ-значение.
  2. Сравнить ключи на равенство (протокол 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:) и ==.
  • Уникальность: Если добавляется элемент с ключом, который уже существует в словаре, его значение перезаписывается.
  • Иммутабельность: Хеш-значение ключа не должно меняться за время его жизни в словаре. Использование мутирующих объектов в качестве ключа — антипаттерн.