В чем разница между Any, Hashable, AnyHashable в Swift 3?

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

Почему Swift представляет AnyHashable?

В чем принципиальная разница между этими тремя терминами?

Разница между Any и AnyHashable?

Разница между Hashable и AnyHashable?

Когда использовать Hashable и когда использовать AnyHashable?

Последнее, но самое запутанное, что означает термин type erased в контексте AnyHashable?

В качестве контекста я следовал предложению Swift Evolution SE-0131.

Ответ 1

Гораздо важнее понять, что они из себя представляют, чем различия между ними.

Any означает "что угодно", начиная от быстрых перечислений, кортежей, замыканий, структур, классов, протоколов и т.д. Каждый тип может быть назначен переменной типа Any.

Hashable - это протокол, который говорит, что "этот объект может быть хеширован, т.е. имеет хеш-код". Если ваш объект может быть хеширован, реализуйте этот протокол, потому что он нужен множеству структур данных (а именно словарей и наборов).

Так что же такое AnyHashable?

Обычно, если вы пытаетесь сделать это:

let a: Set<Hashable>?

это не компилируется. Это потому, что Hashable наследует от Equatable который содержит Self.

Теперь, допустим, вы хотите перенести метод из Objective-C в swift. Этот метод принимает параметр типа NSSet. В Swift это превратится в Set, но каков его общий параметр? Если мы просто поместим Any как мы делаем с NSArray, он не будет работать, потому что объекты Set должны быть хэшируемыми. Но если мы Set<Hashable> он тоже не будет работать, потому что Hashable можно использовать только как общее ограничение. Вот почему они обернули Hashable AnyHashable, который не использует Self и поэтому может использоваться как универсальный параметр.

Относительно того, что означает "тип удален":

Наличие Self в протоколе похоже на протокол с универсальным параметром, а универсальный параметр всегда соответствует классу. Это приводит к невозможности самостоятельного использования протоколов, например Set<Hashable> поскольку "универсальный параметр" неизвестен. AnyHashable решает эту проблему, вообще не используя Self поэтому теперь он становится нормальной структурой. Он "стирает" общий тип Self.

Ответ 2

Any может вообще представлять экземпляр любого типа, включая типы функций. Это говорит нам о том, что значение Any шире, чем значение AnyObject. Любой может представлять что угодно, отсюда и название.

Хотя Any может представлять экземпляр любого типа, он имеет свои ограничения. Вы, вероятно, знаете, что элементы Set и ключи Dictionary должны быть хэшируемыми. Они должны соответствовать протоколу Hashable. Набор нуждается в способности уникально идентифицировать каждый из элементов, которые он содержит. И для поиска значения, связанного с данным ключом, словарь требует, чтобы его ключи были уникальными. Проблема в том, что Any не соответствует этому требованию.

Начиная с Swift 3, стандартная библиотека Swift определяет супертип AnyHashable. Это означает, что типы, соответствующие протоколу Hashable, могут использоваться как AnyHashable. В стандартной библиотеке Swift AnyHashable определяется как структура.

public struct AnyHashable {

    public init<H>(_ base: H) where H : Hashable

    public var base: Any { get }

}

Супертип AnyHashable используется для переноса нетипизированных наборов и словарей из Objective-C в Swift.

Подробнее здесь