Ответ 1
TL; DR; Необязательные параметры в swift преобразуются компилятором в экземпляры Optional
перечислений, и, поскольку Any
может отображаться на любое значение, его можно использовать для хранения необязательных параметров.
Как Swift представляет опционы? Это делает это путем сопоставления SomeType?
Для конкретной реализации Optional
перечисления:
Int? => Optional<Int>
String? => Optional<String>
Упрощенное объявление Optional
выглядит следующим образом:
enum Optional<T> {
case none // nil
case some(T) // non-nil
}
Теперь переменная типа Any
может содержать значение перечисления (или любое другое значение, или даже информацию метатипа), поэтому она должна содержать, например, строку nil
String, aka String?.none
, aka Optional<String>.none
.
Давайте посмотрим, что происходит, хотя. Как мы видим из Optional
объявления, nil
соответствует .none
перечисления .none
для всех типов:
nil == Optional<String>.none // true
nil == Optional<Int>.none // true
[Double]?.none == nil // also true
Теоретически, вы должны иметь возможность назначить nil
для переменной, объявленной как Any
. Тем не менее, компилятор не позволяет этого.
Но почему компилятор не позволяет назначить nil
для переменной Any
? Это потому, что он не может определить, какой тип отображать .none
. Optional
является универсальное перечисление, поэтому ему нужно что-то для заполнения универсального параметра T
, а обычный nil
слишком широкий. Какое значение .none
следует использовать? Один из Int
, другой из String
, другой?
Это дает сообщение об ошибке, подтверждающее вышеприведенный абзац:
let nilAny: Any = nil // error: nil cannot initialize specified type 'Any' (aka 'protocol<>')
Следующий код работает и эквивалентен присвоению nil
:
let nilAny: Any = Optional<Int>.none
как указано выше, Any
переменная фактически содержит допустимое значение Optional
перечисления.
Косвенные назначения также работают, поскольку за кадром nil
преобразуется в Optional<Type>.none
.
var nilableBool: Bool? // nilableBool has the Optional<Bool>.none value
var nilBoolAsAny: Any = nilableBool // the compiler has all the needed type information from nilableBool
В отличие от других языков, в Swift nil
соответствует конкретному значению. Но ему нужен тип для работы, чтобы компилятор знал, какой Optional<T>.none
он должен выделить. Мы можем думать о ключевом слове как о предоставлении синтаксиса сахара.