В чем разница между 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
.
Подробнее здесь