Swift Language
Opcjonalne
Szukaj…
Wprowadzenie
„Opcjonalna wartość albo zawiera wartość, albo zero, wskazując brak wartości”
Fragment: Apple Inc. „Swift Programming Language (wydanie Swift 3.1).” iBooks. https://itun.es/us/k5SW7.l
Podstawowe opcjonalne przypadki użycia obejmują: dla stałej (let), użycie opcjonalnej w pętli (jeśli-let), bezpieczne rozpakowanie opcjonalnej wartości w ramach metody (straż-let) i jako część pętli przełączania (case-let ), domyślnie wartość wynosi zero, przy użyciu operatora koalescencji (??)
Składnia
- var opcjonalnyNazwa: opcjonalnyTyp? // zadeklaruj typ opcjonalny, domyślnie zero
- var opcjonalnyNazwa: opcjonalnyTyp? = wartość // deklaruj opcjonalne z wartością
- var opcjonalnyNazwa: opcjonalnyTyp! // zadeklaruj domyślnie nieopakowane opcjonalne
- opcjonalny! // wymuś rozpakowanie opcjonalnego
Uwagi
Aby uzyskać więcej informacji na temat opcji, zobacz Swift Programming Language .
Rodzaje opcji
Opcjonalne to ogólny typ wyliczenia, który działa jak opakowanie. To opakowanie pozwala zmiennej mieć jeden z dwóch stanów: wartość typu zdefiniowanego przez użytkownika lub nil
, która reprezentuje brak wartości.
Ta umiejętność jest szczególnie ważna w Swift, ponieważ jednym z deklarowanych celów projektowych języka jest dobra współpraca z platformami Apple. Wiele (większość) frameworków Apple wykorzystuje nil
ze względu na łatwość użycia i znaczenie dla wzorców programowania i projektowania API w Objective-C.
W Swift, aby zmienna miała wartość nil
, musi być opcjonalna. Opcjonalnie można utworzyć, dołączając albo !
lub ?
do typu zmiennej. Na przykład, aby uczynić Int
opcjonalnym, możesz użyć
var numberOne: Int! = nil
var numberTwo: Int? = nil
?
opcjonalne muszą być jawnie rozpakowane i powinny być używane, jeśli nie jesteś pewien, czy zmienna będzie miała wartość, kiedy ją uzyskasz. Na przykład po przekształceniu łańcucha w Int
, wynikiem jest opcjonalny Int?
, ponieważ zero zostanie zwrócone, jeśli ciąg nie jest poprawną liczbą
let str1 = "42"
let num1: Int? = Int(str1) // 42
let str2 = "Hello, World!"
let num2: Int? = Int(str2) // nil
!
opcjonalne są automatycznie rozpakowywane i powinny być używane tylko wtedy, gdy masz pewność, że zmienna będzie miała wartość, gdy ją uzyskasz. Na przykład globalny przycisk UIButton!
zmienna zainicjowana w 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)
}
Rozpakowywanie opcjonalnego
Aby uzyskać dostęp do wartości opcji, należy ją rozpakować.
Możesz warunkowo rozpakować Opcjonalne za pomocą opcjonalnego wiązania i wymusić rozpakowanie Opcjonalnego za pomocą !
operator.
Warunkowe rozpakowywanie skutecznie pyta „Czy ta zmienna ma wartość?” podczas wymuszania rozpakowywania mówi „Ta zmienna ma wartość!”.
Jeśli wymusisz rozpakowanie zmiennej, która jest nil
, twój program rzuci nieoczekiwanie znalezione zero podczas rozpakowywania opcjonalnego wyjątku i zawiesi się, więc musisz uważnie rozważyć użycie !
jest odpowiednie.
var text: String? = nil
var unwrapped: String = text! //crashes with "unexpectedly found nil while unwrapping an Optional value"
W celu bezpiecznego rozpakowania można użyć instrukcji if-let
, która nie zgłosi wyjątku ani nie zawiesi się, jeśli zapakowana wartość wynosi 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")
}
Lub oświadczenie straży :
var number: Int?
guard let unwrappedNumber = number else {
return
}
print("number: \(unwrappedNumber)")
Zauważ, że zakres zmiennej unwrappedNumber
znajduje się wewnątrz instrukcji if-let
i poza blokiem guard
.
Możesz rozpakować łańcuch wielu opcji, jest to przydatne głównie w przypadkach, gdy twój kod wymaga więcej niż zmiennej do poprawnego działania:
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.
}
Zauważ, że wszystkie zmienne muszą być rozpakowane, aby pomyślnie przejść test, w przeciwnym razie nie byłoby sposobu, aby określić, które zmienne zostały rozpakowane, a które nie.
Możesz łańcuchować instrukcje warunkowe za pomocą opcji opcjonalnych natychmiast po ich rozpakowaniu. Oznacza to brak zagnieżdżonych instrukcji 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!")
}
Brak operatora koalescencyjnego
Możesz użyć zerowego operatora koalescencyjnego, aby rozpakować wartość, jeśli jest ona inna niż zero, w przeciwnym razie podaj inną wartość:
func fallbackIfNil(str: String?) -> String {
return str ?? "Fallback String"
}
print(fallbackIfNil("Hi")) // Prints "Hi"
print(fallbackIfNil(nil)) // Prints "Fallback String"
Ten operator może zwierać , co oznacza, że jeśli lewy operand jest inny niż zero, prawy operand nie zostanie oceniony:
func someExpensiveComputation() -> String { ... }
var foo : String? = "a string"
let str = foo ?? someExpensiveComputation()
W tym przykładzie, ponieważ foo
ma wartość someExpensiveComputation()
niż zero, someExpensiveComputation()
nie zostaną wywołane.
Możesz także połączyć wiele zerowych instrukcji koalescencyjnych:
var foo : String?
var bar : String?
let baz = foo ?? bar ?? "fallback string"
W tym przykładzie baz
zostanie przypisana nieopakowana wartość foo
jeśli jest ona inna niż zero, w przeciwnym razie zostanie mu przypisana nieopakowana wartość bar
jeśli jest ona inna niż zero, w przeciwnym razie zostanie przypisana wartość zastępcza.
Opcjonalne łączenie
Za pomocą opcjonalnego łączenia można wywoływać metodę , uzyskiwać dostęp do właściwości lub indeksować opcjonalnie. Odbywa się to poprzez umieszczenie ?
pomiędzy podaną zmienną opcjonalną a danym elementem (metoda, właściwość lub indeks dolny).
struct Foo {
func doSomething() {
print("Hello World!")
}
}
var foo : Foo? = Foo()
foo?.doSomething() // prints "Hello World!" as foo is non-nil
Jeśli foo
zawiera wartość, zostanie do niej wywołana doSomething()
. Jeśli foo
jest nil
, nic złego się nie stanie - kod po prostu po cichu zawiedzie i będzie kontynuował wykonywanie.
var foo : Foo? = nil
foo?.doSomething() // will not be called as foo is nil
(Jest to podobne zachowanie jak wysyłanie wiadomości do nil
w Objective-C)
Powodem, dla którego opcjonalne łączenie łańcuchowe jest nazywane, jest to, że „opcjonalność” będzie propagowana przez członków, do których dzwonisz / do których masz dostęp. Oznacza to, że zwracane wartości dowolnych elementów używanych z opcjonalnym łączeniem łańcuchowym będą opcjonalne, niezależnie od tego, czy są wpisane jako opcjonalne czy nie.
struct Foo {
var bar : Int
func doSomething() { ... }
}
let foo : Foo? = Foo(bar: 5)
print(foo?.bar) // Optional(5)
Tutaj foo?.bar
zwraca Int?
nawet jeśli bar
nie jest opcjonalny, ponieważ sam foo
jest opcjonalny.
W miarę propagowania opcjonalności metody zwracające Void
zwrócą Void?
po wywołaniu z opcjonalnym łańcuchem. Może to być przydatne w celu ustalenia, czy metoda została wywołana, czy nie (a zatem, czy opcjonalna ma wartość).
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")
}
Czy porównujemy Void?
zwraca wartość nil
w celu ustalenia, czy metoda została wywołana (a zatem czy foo
jest inne niż zero).
Omówienie - dlaczego opcjonalne?
Często podczas programowania konieczne jest rozróżnienie między zmienną, która ma wartość, a zmienną, która jej nie ma. Dla typów referencyjnych, takich jak Wskaźniki C, można użyć specjalnej wartości, takiej jak null
aby wskazać, że zmienna nie ma żadnej wartości. W przypadku typów wewnętrznych, takich jak liczba całkowita, jest to trudniejsze. Można użyć wartości nominalnej, takiej jak -1, ale zależy to od interpretacji wartości. Eliminuje również tę „specjalną” wartość z normalnego użytkowania.
Aby rozwiązać ten problem, Swift pozwala zadeklarować dowolną zmienną jako opcjonalną. Wskazuje na to użycie znaku? lub! po typie (patrz Rodzaje opcji )
Na przykład,
var possiblyInt: Int?
deklaruje zmienną, która może zawierać wartość całkowitą lub nie.
Specjalna wartość nil
wskazuje, że do tej zmiennej nie jest obecnie przypisana żadna wartość.
possiblyInt = 5 // PossiblyInt is now 5
possiblyInt = nil // PossiblyInt is now unassigned
nil
może być również użyte do przetestowania przypisanej wartości:
if possiblyInt != nil {
print("possiblyInt has the value \(possiblyInt!)")
}
Zwróć uwagę na użycie !
w instrukcji print, aby rozpakować wartość opcjonalną.
Jako przykład powszechnego użycia opcji, rozważ funkcję, która zwraca liczbę całkowitą z ciągu zawierającego cyfry; Możliwe, że ciąg może zawierać znaki niecyfrowe, a nawet może być pusty.
W jaki sposób funkcja zwracająca prosty Int
wskazywać na awarię? Nie można tego zrobić, zwracając określoną wartość, ponieważ uniemożliwiłoby to parsowanie tej wartości z łańcucha.
var someInt
someInt = parseInt("not an integer") // How would this function indicate failure?
Jednak w Swift ta funkcja może po prostu zwrócić opcjonalny Int. Błąd jest wskazywany przez wartość zwracaną 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")
}