Swift Language
Optionals
Поиск…
Вступление
«Необязательное значение либо содержит значение, либо содержит nil, чтобы указать, что значение отсутствует»
Выдержка из: Apple Inc. «Быстрый язык программирования (издание Swift 3.1)». IBooks. https://itun.es/us/k5SW7.l
Основные необязательные варианты использования включают: для константы (let), использование необязательного в цикле (if-let), безопасное развертывание необязательного значения внутри метода (guard-let) и как часть циклов переключения (case-let ), по умолчанию - значение, если nil, используя оператор coalesce (??)
Синтаксис
- var optionalName: optionalType? // объявлять необязательный тип, по умолчанию - nil
- var optionalName: optionalType? = значение // объявляет необязательный параметр со значением
- var optionalName: optionalType! // объявлять неявно развернутый необязательный
- необязательный! // принудительно разворачиваем опцию
замечания
Дополнительные сведения об опциях см. В разделе «Быстрый язык программирования» .
Типы опций
Опционы - это общий тип перечисления, который действует как обертка. Эта оболочка позволяет переменной иметь одно из двух состояний: значение пользовательского типа или nil
, которое представляет отсутствие значения.
Эта способность особенно важна в Swift, потому что одна из заявленных целей дизайна языка - это хорошо работать с каркасами Apple. Многие (большинство) инфраструктур Apple используют nil
из-за простоты использования и значимости для шаблонов программирования и дизайна API в Objective-C.
В Swift для переменной, имеющей значение nil
, она должна быть необязательной. Опционы могут быть созданы путем добавления a !
или ?
к типу переменной. Например, чтобы сделать Int
необязательным, вы можете использовать
var numberOne: Int! = nil
var numberTwo: Int? = nil
?
optionals должны быть явно развернуты и должны использоваться, если вы не уверены, будет ли переменная иметь значение при ее доступе. Например, при преобразовании строки в Int
результат является необязательным значением Int?
, потому что nil будет возвращен, если строка не является допустимым числом
let str1 = "42"
let num1: Int? = Int(str1) // 42
let str2 = "Hello, World!"
let num2: Int? = Int(str2) // nil
!
опции автоматически распаковываются и должны использоваться только тогда, когда вы уверены, что переменная будет иметь значение при ее доступе. Например, глобальный UIButton!
переменная, которая инициализируется в viewDidLoad()
//myButton will not be accessed until viewDidLoad is called,
//so a ! optional can be used here
var myButton: UIButton!
override func viewDidLoad(){
self.myButton = UIButton(frame: self.view.frame)
self.myButton.backgroundColor = UIColor.redColor()
self.view.addSubview(self.myButton)
}
Развертывание необязательного
Чтобы получить доступ к значению необязательного, его необходимо развернуть.
Вы можете условно разворачивать опцию, используя опциональную привязку и разворот силы a Необязательно с помощью !
оператор.
Условно отказоустойчиво спрашивает: «Имеет ли эта переменная ценность?» в то время как развертывание силы говорит: «Эта переменная имеет значение!».
Если вы принудительно разворачиваете переменную, которая равна nil
, ваша программа будет неожиданно обнаруживать нуль при развертывании необязательного исключения и сбоя, поэтому вам следует тщательно подумать, если вы используете !
является целесообразным.
var text: String? = nil
var unwrapped: String = text! //crashes with "unexpectedly found nil while unwrapping an Optional value"
Для безопасного развертывания вы можете использовать оператор if-let
, который не будет генерировать исключение или сбой, если обернутое значение равно nil
:
var number: Int?
if let unwrappedNumber = number { // Has `number` been assigned a value?
print("number: \(unwrappedNumber)") // Will not enter this line
} else {
print("number was not assigned a value")
}
Или заявление охранника :
var number: Int?
guard let unwrappedNumber = number else {
return
}
print("number: \(unwrappedNumber)")
Обратите внимание, что область переменной unwrappedNumber
находится внутри оператора if-let
и вне guard
блока.
Вы можете перехватывать множество опций, это в основном полезно в случаях, когда вашему коду требуется более чем переменная для правильной работы:
var firstName:String?
var lastName:String?
if let fn = firstName, let ln = lastName {
print("\(fn) + \(ln)")//pay attention that the condition will be true only if both optionals are not nil.
}
Обратите внимание, что все переменные должны быть развернуты, чтобы успешно пройти тест, иначе у вас не было бы способа определить, какие переменные были развернуты, а какие нет.
Вы можете связать условные операторы с помощью своих опций сразу же после их разворачивания. Это означает, что нет вложенных операторов if-else!
var firstName:String? = "Bob"
var myBool:Bool? = false
if let fn = firstName, fn == "Bob", let bool = myBool, !bool {
print("firstName is bob and myBool was false!")
}
Nil Coalescing Operator
Вы можете использовать оператор объединения nil для разворачивания значения, если он не равен нулю, иначе укажите другое значение:
func fallbackIfNil(str: String?) -> String {
return str ?? "Fallback String"
}
print(fallbackIfNil("Hi")) // Prints "Hi"
print(fallbackIfNil(nil)) // Prints "Fallback String"
Этот оператор способен к короткому замыканию , что означает, что если левый операнд не равен нулю, правый операнд не будет оцениваться:
func someExpensiveComputation() -> String { ... }
var foo : String? = "a string"
let str = foo ?? someExpensiveComputation()
В этом примере, поскольку foo
равен нулю, someExpensiveComputation()
не будет вызываться.
Вы также можете объединить несколько операторов объединения nil:
var foo : String?
var bar : String?
let baz = foo ?? bar ?? "fallback string"
В этом примере baz
будет присвоено развернутое значение foo
если оно не равно nil, иначе ему будет присвоено развернутое значение bar
если оно не равно nil, иначе ему будет присвоено значение возврата.
Необязательная цепочка
Вы можете использовать Необязательный Chaining , чтобы вызвать метод , получить доступ к свойству или индексам как необязательный. Это делается путем размещения ?
между данной необязательной переменной и данным элементом (метод, свойство или индекс).
struct Foo {
func doSomething() {
print("Hello World!")
}
}
var foo : Foo? = Foo()
foo?.doSomething() // prints "Hello World!" as foo is non-nil
Если foo
содержит значение, на doSomething()
будет вызываться doSomething()
. Если foo
равно nil
, тогда ничего плохого не произойдет - код просто терпит неудачу и продолжит выполнение.
var foo : Foo? = nil
foo?.doSomething() // will not be called as foo is nil
(Это похоже на поведение отправки сообщений в nil
в Objective-C)
Причина, по которой «Факультативный цепочек» называется как таковой, заключается в том, что «опциональность» будет распространяться через членов, которые вы вызываете / получаете доступ. Это означает, что возвращаемые значения любых членов, используемых с опциональной цепочкой, будут необязательными, независимо от того, набираются ли они как необязательные или нет.
struct Foo {
var bar : Int
func doSomething() { ... }
}
let foo : Foo? = Foo(bar: 5)
print(foo?.bar) // Optional(5)
Здесь foo?.bar
возвращает Int?
даже если bar
является необязательным, поскольку сам foo
является необязательным.
Когда опциональность распространяется, методы, возвращающие Void
, вернут Void?
при вызове с опциональной цепочкой. Это может быть полезно для определения того, был ли вызван метод или нет (и, следовательно, если опция имеет значение).
let foo : Foo? = Foo()
if foo?.doSomething() != nil {
print("foo is non-nil, and doSomething() was called")
} else {
print("foo is nil, therefore doSomething() wasn't called")
}
Здесь мы сравниваем Void?
возвращаемое значение с помощью nil
, чтобы определить, был ли вызван метод (и, следовательно, foo
равен нулю).
Обзор - Почему варианты?
Часто при программировании необходимо провести некоторое различие между переменной, которая имеет значение, а другая - нет. Для ссылочных типов, таких как C-указатели, специальное значение, такое как null
может использоваться для указания того, что переменная не имеет значения. Для внутренних типов, таких как целое число, это сложнее. Номинальное значение, такое как -1, может использоваться, но это зависит от интерпретации значения. Он также устраняет это «особое» значение от нормального использования.
Чтобы решить эту проблему, Swift позволяет объявлять любую переменную как необязательную. Об этом свидетельствует использование a? или же ! после типа (см. Типы опций )
Например,
var possiblyInt: Int?
объявляет переменную, которая может содержать или не содержать целочисленное значение.
Специальное значение nil
указывает, что в настоящее время для этой переменной не назначено значение.
possiblyInt = 5 // PossiblyInt is now 5
possiblyInt = nil // PossiblyInt is now unassigned
nil
также может использоваться для проверки назначенного значения:
if possiblyInt != nil {
print("possiblyInt has the value \(possiblyInt!)")
}
Обратите внимание на использование !
в инструкции печати, чтобы развернуть необязательное значение.
В качестве примера общего использования опций используйте функцию, возвращающую целое число из строки, содержащей цифры; Возможно, что строка может содержать нецифровые символы или даже быть пустым.
Как функция, возвращающая простой Int
указывает на сбой? Он не может этого сделать, возвращая какое-либо конкретное значение, поскольку это исключает возможность анализа этого значения из строки.
var someInt
someInt = parseInt("not an integer") // How would this function indicate failure?
Однако в Swift эта функция может просто вернуть необязательный Int. Тогда отказ указывается возвращаемым значением nil
.
var someInt?
someInt = parseInt("not an integer") // This function returns nil if parsing fails
if someInt == nil {
print("That isn't a valid integer")
}