Опционалы, или опциональные типы данных — это специальный механизм Swift, используемый в тех случаях, когда некоторое значение может существовать, а может и отсутствовать. Для работы со значением, хранящимся внутри опционала, его необходимо извлечь/развернуть (произвести unwrap).
Любой тип данных может стать базовым для опционала, т.е. опциональный тип может быть создан на основе совершенно любого типа данных.
Вариант 1. С помощью конструкции Optional<T>
var value: Optional = 5 var value = Optional(5)
Вариант 2. С помощью конструкции T?
var value = Int?(5)
где T
— тип данных, на основе которого создается опционал.
Вариант 2 (T?
) является синтаксическим сахаром, упрощающим работу с опционалами.
Вариант 1. Опциональное связывание с помощью конструкции if let
if let unwrapValue = optionalValue { print(unwrapValue) }
Вариант 2. Опциональное связывание с помощью конструкции guard let
guard let unwrapValue = optionalValue else { return }
Вариант 3. Принудительное извлечение (force unwrap)
optionalValue!
Вариант 4. Косвенное извлечение (implicitly unwrap)
var optionalValue: Int! = 5 // при обращении к a значение будет автоматически неявно извлекаться optionalValue // 5
Вариант 5. Объединение с nil
(nil coalescing)
optionalValue ?? 5
Не лишним будет упомянуть о следующих вариантах доступа к опциональным значениям
Вариант 6. Опциональные цепочки
a?.someMethod()
Вариант 7. Извлечение c операторами as
и try
optionalValue as! UInt try! optionalValue.someMethod()
В качестве пример можно рассмотреть некую функцию загрузки значения из базы данных. Она возвращает nil
, если соответствующее значение не найдено в базе, и значение опционального типа – если найдено.
С точки зрения внутренней структуры Optional – это перечисление (enum), имеющий два возможных значения: none
и some(T)
, где T
– базовый для опционала тип данных. Данное перечисление подписано на протокол ExpressibleByNilLiteral
, что позволяет ему в качестве значения иметь nil
.
enum NewOptional: ExpressibleByNilLiteral { case some(T) case none init(nilLiteral: ()) { self = .none } init(_ some: T) { self = .some(some) } } let newOptionalValue = NewOptional(6)