★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
➤微信公眾號:山青詠芝(shanqingyongzhi)
➤博客園地址:山青詠芝(https://www.cnblogs.com/strengthen/)
➤GitHub地址:https://github.com/strengthen/LeetCode
➤原文地址:https://www.cnblogs.com/strengthen/p/9711776.html
➤如果鏈接不是山青詠芝的博客園地址,則可能是爬取作者的文章。
➤原文已修改更新!強烈建議點擊原文地址閱讀!支持作者!支持原創!
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★
Swift是用於iOS,macOS,watchOS和tvOS應用程序開發的新編程語言。盡管如此,從您在C和Objective-C方面的開發經驗中,您會熟悉Swift的許多部分。
雨燕提供了自己的所有基本C和Objective-C類型的版本,包括Int
為整數,Double
並Float
為浮點值,Bool
布爾值,並String
為文本數據。雨燕還提供了三種主要類型的集合強大的版本Array
,Set
和Dictionary
,如在集合類型。
與C一樣,Swift使用變量來存儲和引用具有標識名稱的值。Swift還大量使用了無法更改其值的變量。這些被稱為常量,並且比C中的常量功能強大得多。在整個Swift中使用常量可以使代碼在使用不需要更改的值時更安全,更清晰。
除了熟悉的類型外,Swift還引入了在Objective-C中找不到的高級類型,例如元組。元組使您可以創建和傳遞值分組。您可以使用元組從一個函數返回多個值作為單個復合值。
Swift還引入了可選類型,用於處理缺少值的情況。選配說要么“有是一個值,它等於X ”或“有沒有一個價值可言”。nil
在Objective-C中使用可選與在指針中使用類似,但是它們適用於任何類型,而不僅僅是類。可選控件不僅比nil
Objective-C中的指針更安全,更富有表現力,而且它們是Swift最強大的功能的核心。
Swift是一種類型安全的語言,這意味着該語言可幫助您弄清代碼可以使用的值的類型。如果代碼的一部分需要使用String
,則類型安全性可防止您Int
誤將其傳遞。同樣,類型安全性可防止您意外地將可選參數傳遞String
給需要非可選參數的代碼String
。類型安全性可幫助您在開發過程中盡早發現並修復錯誤。
常量和變量
常量和變量將名稱(例如maximumNumberOfLoginAttempts
或welcomeMessage
)與特定類型的值(例如數字10
或字符串"Hello"
)相關聯。常量的值一旦設置就無法更改,而將來可以將變量設置為其他值。
聲明常量和變量
常量和變量必須在使用前聲明。您可以使用let
關鍵字聲明常量,並使用關鍵字聲明變量var
。這是一個示例,說明如何使用常量和變量來跟蹤用戶進行的登錄嘗試次數:
- let maximumNumberOfLoginAttempts = 10
- var currentLoginAttempt = 0
此代碼可以讀取為:
“聲明一個名為的新常數maximumNumberOfLoginAttempts
,並為其賦予值10
。然后,聲明一個名為的新變量currentLoginAttempt
,並為其賦予初始值0
。”
在此示例中,將允許的最大登錄嘗試次數聲明為一個常量,因為最大值不會更改。當前的登錄嘗試計數器被聲明為變量,因為在每次失敗的登錄嘗試之后都必須將該值遞增。
您可以在一行中聲明多個常量或多個變量,並用逗號分隔:
- var x = 0.0, y = 0.0, z = 0.0
注意
如果代碼中的存儲值不變,請始終使用let
關鍵字將其聲明為常量。僅將變量用於存儲需要更改的值。
類型注釋
聲明常量或變量時,可以提供類型注釋,以明確常量或變量可以存儲的值的類型。通過在常量或變量名稱后加冒號,后跟空格,后跟要使用的類型的名稱來編寫類型注釋。
本示例為名為的變量提供類型注釋welcomeMessage
,以指示該變量可以存儲String
值:
- var welcomeMessage: String
聲明中的冒號表示“…類型……”,因此上面的代碼可以讀取為:
“聲明一個名為welcomeMessage
type 的變量String
。”
“類型String
”一詞的意思是“可以存儲任何String
值”。可以將其視為可以存儲的“事物的類型”(或“事物的類型”)。
welcomeMessage
現在可以將變量設置為任何字符串值,而不會出現錯誤:
- welcomeMessage = "Hello"
您可以在一行上定義多個相同類型的相關變量,並用逗號分隔,並在最終變量名稱后添加一個類型注釋:
- var red, green, blue: Double
注意
在實踐中很少需要編寫類型注釋。如果在定義的點為常量或變量提供初始值,Swift幾乎總是可以推斷出用於該常量或變量的類型,如Type Safety和Type Inference中所述。在welcomeMessage
上面的示例中,沒有提供初始值,因此該welcomeMessage
變量的類型是通過類型注釋指定的,而不是從初始值推斷出來的。
命名常量和變量
常量和變量名稱幾乎可以包含任何字符,包括Unicode字符:
- let π = 3.14159
- let 你好 = "你好世界"
- let 🐶🐮 = "dogcow"
常量和變量名稱不能包含空格字符,數學符號,箭頭,專用的Unicode標量值或線條和框形圖字符。它們也不能以數字開頭,盡管數字可能包含在名稱中的其他位置。
聲明了某種類型的常量或變量后,就無法再次使用相同的名稱對其進行聲明,也無法對其進行更改以存儲其他類型的值。也不能將常量更改為變量或將變量更改為常量。
注意
如果需要為常量或變量提供與保留的Swift關鍵字相同的名稱,則`
在使用該關鍵字作為名稱時,請在關鍵字兩端加上反引號()。但是,除非絕對沒有選擇,否則避免將關鍵字用作名稱。
您可以將現有變量的值更改為兼容類型的另一個值。在此示例中,的值friendlyWelcome
從更改"Hello!"
為"Bonjour!"
:
- var friendlyWelcome = "Hello!"
- friendlyWelcome = "Bonjour!"
- // friendlyWelcome is now "Bonjour!"
與變量不同,常數的值在設置后不能更改。編譯代碼時,嘗試這樣做會報告為錯誤:
- let languageName = "Swift"
- languageName = "Swift++"
- // This is a compile-time error: languageName cannot be changed.
打印常量和變量
您可以使用以下print(_:separator:terminator:)
函數打印常量或變量的當前值:
- print(friendlyWelcome)
- // Prints "Bonjour!"
該print(_:separator:terminator:)
函數是全局函數,它將一個或多個值打印到適當的輸出。例如,在Xcode中,該print(_:separator:terminator:)
函數在Xcode的“控制台”窗格中打印其輸出。該separator
和terminator
參數都有默認值,這樣你就可以當你調用這個函數忽略它們。默認情況下,該函數通過添加換行符來終止其打印的行。要打印后沒有換行符的值,請傳遞一個空字符串作為終止符,例如。有關具有默認值的參數的信息,請參見“ 默認參數值”。print(someValue, terminator: "")
Swift使用字符串插值法將常量或變量的名稱作為較長字符串中的占位符,並提示Swift將其替換為該常量或變量的當前值。將名稱括在括號中,並在左括號前使用反斜杠將其轉義:
- print("The current value of friendlyWelcome is \(friendlyWelcome)")
- // Prints "The current value of friendlyWelcome is Bonjour!"
注意
你可以用串插中使用的所有選項中描述字符串插值。
注釋
使用注釋在代碼中包含不可執行的文本,作為對自己的注釋或提醒。編譯代碼時,Swift編譯器將忽略注釋。
Swift中的注釋與C中的注釋非常相似。單行注釋以兩個正斜杠(//
)開頭:
- // This is a comment.
多行注釋以正斜杠后跟星號(/*
)開頭,以星號后跟正斜杠(*/
)結束:
- /* This is also a comment
- but is written over multiple lines. */
與C語言中的多行注釋不同,Swift中的多行注釋可以嵌套在其他多行注釋中。通過開始多行注釋塊,然后在第一個塊中開始第二個多行注釋來編寫嵌套注釋。然后關閉第二個塊,然后關閉第一個塊:
- /* This is the start of the first multiline comment.
- /* This is the second, nested multiline comment. */
- This is the end of the first multiline comment. */
嵌套的多行注釋使您可以快速,輕松地注釋掉大塊代碼,即使代碼已經包含多行注釋。
分號
與許多其他語言不同,Swift不需要您;
在代碼中的每個語句后寫分號(),盡管您可以根據需要這樣做。但是,如果要在一行上編寫多個單獨的語句,則需要分號:
- let cat = "🐱"; print(cat)
- // Prints "🐱"
整數
整數是沒有小數部分的整數,例如42
和-23
。整數是帶符號的(正,零或負)或無符號的(正或零)。
Swift提供8位,16位,32位和64位形式的有符號和無符號整數。這些整數遵循類似於C的命名約定,其中8位無符號整數的類型為UInt8
,而32位有符號整數的類型為Int32
。像Swift中的所有類型一樣,這些整數類型都有大寫的名稱。
整數范圍
您可以使用min
和max
屬性訪問每個整數類型的最小值和最大值:
- let minValue = UInt8.min // minValue is equal to 0, and is of type UInt8
- let maxValue = UInt8.max // maxValue is equal to 255, and is of type UInt8
這些屬性的值具有適當大小的數字類型(例如,UInt8
在上面的示例中),因此可以與相同類型的其他值一起在表達式中使用。
整數
在大多數情況下,您無需選擇特定大小的整數即可在代碼中使用。Swift提供了額外的整數類型,Int
其大小與當前平台的本機字大小相同:
- 在32位平台上,
Int
與大小相同Int32
。 - 在64位平台上,
Int
與大小相同Int64
。
除非您需要使用特定大小的整數,否則請始終Int
在代碼中使用整數值。這有助於代碼的一致性和互操作性。即使在32位平台上,Int
也可以存儲-2,147,483,648
和之間的任何值2,147,483,647
,並且對於許多整數范圍而言足夠大。
UInt
Swift還提供了一個無符號整數類型,UInt
其大小與當前平台的本機字大小相同:
- 在32位平台上,
UInt
與大小相同UInt32
。 - 在64位平台上,
UInt
與大小相同UInt64
。
注意
使用UInt
只有當你特別需要具有相同大小的平台的本地字大小的無符號整型。如果不是這種情況,那么Int
即使已知要存儲的值是非負值,也還是首選。始終如一地使用Int
整數值有助於代碼互操作性,避免了在不同數字類型之間進行轉換的需要,並匹配了整數類型推斷,如Type Safety和Type Inference中所述。
浮點數字
浮點數是具有小數部分的數字,例如3.14159
,0.1
,和-273.15
。
浮點類型可以代表比整數類型更大的值范圍,並且可以存儲比可以存儲的數字大或小的數字Int
。Swift提供了兩種帶符號的浮點數類型:
Double
表示一個64位浮點數。Float
表示一個32位浮點數。
注意
Double
的精度至少為15個十進制數字,而的精度Float
則可以低至6個十進制數字。要使用的適當浮點類型取決於您需要在代碼中使用的值的性質和范圍。在任何一種類型都適合的情況下,Double
首選。
類型安全性和類型推斷
Swift是一種類型安全的語言。類型安全的語言鼓勵您清楚代碼可以使用的值的類型。如果您的代碼的一部分需要使用String
,則不能Int
錯誤地傳遞它。
由於Swift是類型安全的,因此它會在編譯代碼時執行類型檢查,並將所有不匹配的類型標記為錯誤。這使您能夠在開發過程中盡早發現並修復錯誤。
使用不同類型的值時,類型檢查可幫助您避免錯誤。但是,這並不意味着您必須指定聲明的每個常量和變量的類型。如果您未指定所需的值類型,則Swift會使用類型推斷來得出適當的類型。通過類型推斷,編譯器只需檢查您提供的值,即可在編譯代碼時自動推斷出特定表達式的類型。
由於類型推斷,Swift與C或Objective-C等語言相比,所需的類型聲明要少得多。常量和變量仍然是顯式輸入的,但是指定它們的類型的許多工作都是為您完成的。
當聲明具有初始值的常量或變量時,類型推斷特別有用。這通常是通過在您聲明常量或變量的位置為其分配常量值(或literal)來完成的。(A字面值是直接出現在源代碼中,如一個值42
和3.14159
在下面的例子。)
例如,如果您不給42
新常量指定字面值而沒有說出它是什么類型,Swift就會推斷您希望該常量為Int
,因為您已經用一個看起來像整數的數字對其進行了初始化:
- let meaningOfLife = 42
- // meaningOfLife is inferred to be of type Int
同樣,如果您沒有為浮點文字指定類型,Swift會推斷您要創建一個Double
:
- let pi = 3.14159
- // pi is inferred to be of type Double
在推斷浮點數的類型時,Swift總是選擇Double
(而不是Float
)。
如果在表達式中結合使用整數和浮點文字,Double
則會從上下文中推斷出的類型:
- let anotherPi = 3 + 0.14159
- // anotherPi is also inferred to be of type Double
的字面值3
本身沒有明確的類型,因此Double
從浮點字面量作為加法的一部分可以推斷出適當的輸出類型。
數字文字
整數文字可以寫為:
- 一個十進制數,無前綴
- 一個二進制數,有
0b
前綴 - 一個八進制數,有
0o
前綴 - 一個十六進制數,有
0x
前綴
所有這些整數文字的十進制值為17
:
- let decimalInteger = 17
- let binaryInteger = 0b10001 // 17 in binary notation
- let octalInteger = 0o21 // 17 in octal notation
- let hexadecimalInteger = 0x11 // 17 in hexadecimal notation
浮點文字可以是十進制(不帶前綴)或十六進制(帶0x
前綴)。它們的小數點兩側必須始終有一個數字(或十六進制數字)。小數浮點數也可以有一個可選的指數,用大寫或小寫表示e
; 十六進制浮點數必須具有指數,以大寫或小寫表示p
。
對於指數為的十進制數字exp
,基數乘以10 exp:
1.25e2
表示1.25 x 10 2,或125.0
。1.25e-2
表示1.25 x 10 -2,或0.0125
。
對於指數為的十六進制數exp
,將基數乘以2 exp:
0xFp2
表示15 x 2 2,或60.0
。0xFp-2
表示15 x 2 -2,或3.75
。
所有這些浮點文字的十進制值為12.1875
:
- let decimalDouble = 12.1875
- let exponentDouble = 1.21875e1
- let hexadecimalDouble = 0xC.3p0
數字文字可以包含額外的格式,以使其更易於閱讀。整數和浮點數都可以用額外的零填充,並且可以包含下划線以幫助提高可讀性。兩種格式都不影響文字的基礎值:
- let paddedDouble = 000123.456
- let oneMillion = 1_000_000
- let justOverOneMillion = 1_000_000.000_000_1
數值類型轉換
將Int
類型用於代碼中的所有通用整數常量和變量,即使已知它們是非負數也是如此。在日常情況下使用默認整數類型意味着整數常量和變量可立即在代碼中互操作,並且將與推斷的類型匹配整數文字值。
僅當由於外部數據的顯式大小的數據,性能,內存使用或其他必要的優化而特別需要處理其他任務時,才使用其他整數類型。在這些情況下,使用顯式大小的類型有助於捕獲任何意外的值溢出,並隱式記錄所使用數據的性質。
整數轉換
對於每種數字類型,可以存儲在整數常量或變量中的數字范圍是不同的。一個Int8
常數或變量可以存儲之間的數字-128
和127
,而UInt8
常數或變量可以存儲之間的數字0
和255
。編譯代碼時,將不適合整數大小或常量類型的常量的數字報告為錯誤:
- let cannotBeNegative: UInt8 = -1
- // UInt8 cannot store negative numbers, and so this will report an error
- let tooBig: Int8 = Int8.max + 1
- // Int8 cannot store a number larger than its maximum value,
- // and so this will also report an error
由於每種數字類型可以存儲不同范圍的值,因此您必須視情況選擇加入數字類型轉換。這種選擇加入的方法可以防止隱藏的轉換錯誤,並有助於在代碼中明確表明類型轉換意圖。
要將一種特定的數字類型轉換為另一種,可以使用現有值初始化所需類型的新數字。在下面的示例中,常量twoThousand
是type UInt16
,而常量one
是type UInt8
。它們不能直接添加在一起,因為它們不是同一類型。相反,此示例調用UInt16(one)
創建一個新UInt16
的one
,並使用值初始化,並使用該值代替原始值:
- let twoThousand: UInt16 = 2_000
- let one: UInt8 = 1
- let twoThousandAndOne = twoThousand + UInt16(one)
因為加法的雙方現在都是type UInt16
,所以允許加法。輸出常量(twoThousandAndOne
)推斷為type UInt16
,因為它是兩個UInt16
值的總和。
SomeType(ofInitialValue)
是調用Swift類型的初始化程序並傳遞初始值的默認方法。在幕后,UInt16
有一個接受UInt8
值的初始值設定項,因此該初始值設定項用於UInt16
從現有產生一個新值UInt8
。但是,您不能在此處傳遞任何類型-它必須是為其UInt16
提供初始化程序的類型。擴展中介紹了擴展現有類型以提供接受新類型(包括您自己的類型定義)的初始化程序。
整數和浮點轉換
整數和浮點數字類型之間的轉換必須明確:
- let three = 3
- let pointOneFourOneFiveNine = 0.14159
- let pi = Double(three) + pointOneFourOneFiveNine
- // pi equals 3.14159, and is inferred to be of type Double
在這里,常量的值three
用於創建type的新值Double
,以便加法的兩面都屬於同一類型。如果沒有這種轉換,則不允許添加。
浮點數到整數的轉換也必須明確。整數類型可以使用Double
或Float
值初始化:
- let integerPi = Int(pi)
- // integerPi equals 3, and is inferred to be of type Int
以這種方式初始化新的整數值時,浮點值始終會被截斷。這意味着4.75
成為4
,-3.9
成為-3
。
注意
組合數字常量和變量的規則與數字文字的規則不同。文字值3
可以直接添加到文字值中0.14159
,因為數字文字本身本身沒有顯式類型。僅在編譯器對其求值時才推斷出它們的類型。
類型別名
類型別名為現有類型定義備用名稱。您可以使用typealias
關鍵字定義類型別名。
當您想通過上下文更合適的名稱來引用現有類型時,例如使用外部源中特定大小的數據時,類型別名非常有用:
- typealias AudioSample = UInt16
定義類型別名后,您可以在任何可能使用原始名稱的地方使用別名:
- var maxAmplitudeFound = AudioSample.min
- // maxAmplitudeFound is now 0
在這里,AudioSample
被定義為的別名UInt16
。因為它是一個別名,調用AudioSample.min
實際調用UInt16.min
,它提供的初始值0
的maxAmplitudeFound
變量。
布爾值
Swift具有一個基本的布爾類型,稱為Bool
。布爾值被稱為邏輯值,因為它們只能是true或false。Swift提供了兩個布爾常量值,true
以及false
:
- let orangesAreOrange = true
- let turnipsAreDelicious = false
該類型的orangesAreOrange
和turnipsAreDelicious
被推斷為Bool
一個事實,即他們與布爾文字值初始化。正如Int
和Double
上面,你並不需要聲明常量或變量Bool
,如果將其設置為true
或者false
只要你創建它們。當類型推斷使用其類型已知的其他值初始化常量或變量時,類型推斷有助於使Swift代碼更簡潔易讀。
當您使用條件語句(例如,if
語句)時,布爾值特別有用:
- if turnipsAreDelicious {
- print("Mmm, tasty turnips!")
- } else {
- print("Eww, turnips are horrible.")
- }
- // Prints "Eww, turnips are horrible."
有條件的語句(如if
語句)在“ 控制流”中有更詳細的介紹。
Swift的類型安全性可防止將非布爾值替換為Bool
。下面的示例報告一個編譯時錯誤:
- let i = 1
- if i {
- // this example will not compile, and will report an error
- }
但是,下面的替代示例是有效的:
- let i = 1
- if i == 1 {
- // this example will compile successfully
- }
比較的結果是type ,因此第二個示例通過了type-check。基本運算符中討論了類似的比較。i == 1
Bool
i == 1
與Swift中的其他類型安全示例一樣,這種方法避免了意外錯誤,並確保始終清楚特定代碼段的意圖。
元組
元組將多個值分組為一個復合值。元組中的值可以是任何類型,而不必彼此相同。
在此示例中,是描述HTTP狀態代碼的元組。HTTP狀態代碼是每當您請求網頁時由Web服務器返回的特殊值。如果您請求的網頁不存在,則返回狀態碼。(404, "Not Found")
404 Not Found
- let http404Error = (404, "Not Found")
- // http404Error is of type (Int, String), and equals (404, "Not Found")
的元組基團一起的和,得到的HTTP狀態代碼兩個獨立的值:一個數字和一個人類可讀的描述。可以將其描述為“類型的元組”。(404, "Not Found")
Int
String
(Int, String)
您可以從任何類型的排列創建元組,並且它們可以包含任意多個不同的類型。沒有什么阻止你有型的元組,或者,或者你確實需要的任何其他排列。(Int, Int, Int)
(String, Bool)
您可以將元組的內容分解為單獨的常量或變量,然后像往常一樣訪問它們:
- let (statusCode, statusMessage) = http404Error
- print("The status code is \(statusCode)")
- // Prints "The status code is 404"
- print("The status message is \(statusMessage)")
- // Prints "The status message is Not Found"
如果只需要一些元組的值,則_
在分解元組時,請用下划線()忽略該元組的某些部分:
- let (justTheStatusCode, _) = http404Error
- print("The status code is \(justTheStatusCode)")
- // Prints "The status code is 404"
或者,使用從零開始的索引號訪問元組中的各個元素值:
- print("The status code is \(http404Error.0)")
- // Prints "The status code is 404"
- print("The status message is \(http404Error.1)")
- // Prints "The status message is Not Found"
定義元組時,可以命名元組中的各個元素:
- let http200Status = (statusCode: 200, description: "OK")
如果在元組中命名元素,則可以使用元素名稱來訪問這些元素的值:
- print("The status code is \(http200Status.statusCode)")
- // Prints "The status code is 200"
- print("The status message is \(http200Status.description)")
- // Prints "The status message is OK"
元組作為函數的返回值特別有用。嘗試檢索網頁的函數可能會返回元組類型,以描述頁面檢索的成功或失敗。通過返回具有兩個不同值(每個類型都不同)的元組,該函數提供的結果要比僅返回單個類型的單個值要有用得多。有關更多信息,請參見具有多個返回值的函數。(Int, String)
注意
元組對於簡單的一組相關值很有用。它們不適合創建復雜的數據結構。如果您的數據結構可能更復雜,則將其建模為類或結構,而不是元組。有關更多信息,請參見結構和類。
選裝件
您可以在不存在值的情況下使用可選選項。可選的代表兩種可能性:要么有是一個值,你可以解開可選訪問該值,或者有沒有價值可言。
注意
可選的概念在C或Objective-C中不存在。在Objective-C中,最接近的是nil
從一種方法返回的能力,該方法原本會返回一個對象,nil
意思是“缺少有效的對象”。但是,這僅適用於對象,不適用於結構,基本C類型或枚舉值。對於這些類型,Objective-C方法通常返回一個特殊值(例如NSNotFound
)來指示沒有值。這種方法假定方法的調用者知道要測試的特殊值,並且記住要進行檢查。Swift的可選參數使您可以指示根本不需要任何類型的值,而無需特殊的常量。
這是一個示例,說明如何使用可選參數來應對缺少值的情況。Swift的Int
類型具有一個初始化程序,該初始化程序試圖將一個String
值轉換為一個Int
值。但是,並非每個字符串都可以轉換為整數。字符串"123"
可以轉換為數值123
,但是字符串沒有明顯的數值可以轉換為數值。"hello, world"
以下示例使用初始化程序嘗試將a String
轉換為Int
:
- let possibleNumber = "123"
- let convertedNumber = Int(possibleNumber)
- // convertedNumber is inferred to be of type "Int?", or "optional Int"
由於初始化程序可能失敗,因此它返回一個optional Int
而不是一個Int
。可選Int
內容寫為Int?
,而不是Int
。問號表示它包含的值是可選的,這意味着它可能包含某個 Int
值,或者可能根本不包含任何值。(它不能包含其他任何內容,例如Bool
值或String
值。它可以是Int
,也可以完全不包含任何內容。)
零
您可以通過為可選變量分配特殊值來將其設置為無值狀態nil
:
- var serverResponseCode: Int? = 404
- // serverResponseCode contains an actual Int value of 404
- serverResponseCode = nil
- // serverResponseCode now contains no value
注意
您不能使用nil
非可選的常量和變量。如果在某些情況下代碼中的常量或變量需要在沒有值的情況下工作,請始終將其聲明為適當類型的可選值。
如果定義一個可選變量而不提供默認值,則該變量將自動nil
為您設置為:
- var surveyAnswer: String?
- // surveyAnswer is automatically set to nil
注意
Swift nil
與nil
Objective-C中的不一樣。在Objective-C中,nil
是指向不存在對象的指針。在Swift中,nil
它不是指針,而是缺少某種類型的值。可以將任何類型的Optionals 設置為nil
,而不僅僅是對象類型。
如果語句和強制展開
您可以使用一條if
語句,通過將可選內容與進行比較,找出可選內容是否包含值nil
。您可以使用“等於”運算符(==
)或“不等於”運算符(!=
)進行比較。
如果一個可選參數有一個值,則認為它是“不等於” nil
:
- if convertedNumber != nil {
- print("convertedNumber contains some integer value.")
- }
- // Prints "convertedNumber contains some integer value."
一旦確定可選選項確實包含一個值,就可以通過!
在可選名稱的末尾添加一個感嘆號()來訪問其基礎值。感嘆號有效地表示:“我知道此可選選項肯定具有價值;請使用它。” 這稱為可選值的強制展開:
- if convertedNumber != nil {
- print("convertedNumber has an integer value of \(convertedNumber!).")
- }
- // Prints "convertedNumber has an integer value of 123."
有關該if
語句的更多信息,請參見控制流。
注意
嘗試用於!
訪問不存在的可選值會觸發運行時錯誤。在強制解開其可選nil
值之前,請始終確保其包含非!
值。
可選裝訂
您可以使用可選綁定來確定可選對象是否包含值,如果包含,則使該值可用作臨時常量或變量。可選綁定可以與if
and while
語句一起使用,以檢查可選內部的值,並將該值提取到常量或變量中,作為單個操作的一部分。if
和while
語句在控制流中更詳細地描述。
為if
語句編寫一個可選的綁定,如下所示:
- if let constantName = someOptional {
- statements
- }
您可以possibleNumber
從Optionals部分重寫示例,以使用可選綁定而不是強制展開:
- if let actualNumber = Int(possibleNumber) {
- print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)")
- } else {
- print("The string \"\(possibleNumber)\" could not be converted to an integer")
- }
- // Prints "The string "123" has an integer value of 123"
此代碼可以讀取為:
“如果Int
返回的可選Int(possibleNumber)
內容包含一個值,請為該可選內容中包含的值設置一個新的常量actualNumber
。”
如果轉換成功,則該actualNumber
常量可在if
語句的第一分支中使用。它已經被初始化與包含在值內可選的,因此沒有必要使用!
后綴來訪問它的價值。在此示例中,actualNumber
僅用於打印轉換結果。
您可以將常量和變量與可選綁定一起使用。如果要操作語句actualNumber
的第一個分支內的值,則if
可以編寫,而可選值中包含的值將作為變量而不是常量提供。if var actualNumber
您可以根據需要在單個if
語句中包含盡可能多的可選綁定和布爾條件,以逗號分隔。如果可選綁定中的nil
任何值是或任何布爾條件求和false
,則整個if
語句的條件視為false
。以下if
語句是等效的:
- if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
- print("\(firstNumber) < \(secondNumber) < 100")
- }
- // Prints "4 < 42 < 100"
- if let firstNumber = Int("4") {
- if let secondNumber = Int("42") {
- if firstNumber < secondNumber && secondNumber < 100 {
- print("\(firstNumber) < \(secondNumber) < 100")
- }
- }
- }
- // Prints "4 < 42 < 100"
注意
在if
語句中使用可選綁定創建的常量和變量僅在if
語句主體內可用。相反,用guard
語句創建的常量和變量在該語句之后的代碼行中可用guard
,如Early Exit中所述。
隱式展開的可選
如上所述,可選的指示常量或變量被允許具有“無值”。可以使用if
語句檢查可選項以查看值是否存在,並且可以使用可選綁定有條件地對其進行拆包,以訪問可選值(如果存在)。
有時,從程序的結構中可以明顯看出,在首次設置可選值之后,該可選值將始終具有一個值。在這些情況下,刪除每次訪問可選值時都不需要檢查和取消包裝的值很有用,因為可以安全地假定它始終都具有值。
這些類型的可選定義為隱式展開的可選。通過在要設置為可選的類型之后放置感嘆號(String!
)而不是問號(String?
),可以隱式地解開可選的內容。聲明時,不要在選項的名稱之后放置一個感嘆號,而是在選項的類型之后放置感嘆號。
當在定義了可選值之后立即確認該可選值的存在並且可以肯定地假定此后的每個點都存在時,隱式解開的可選值很有用。Swift中隱式解包的可選對象的主要用途是在類初始化期間,如無主引用和隱式解開的可選屬性中所述。
隱式解開的可選內容是幕后的常規可選內容,但也可以像非可選值一樣使用,而無需在每次訪問它時都將其解包。下面的示例顯示了在以顯式方式訪問其包裝值時,可選字符串和隱式解包的可選字符串在行為上的區別String
:
- let possibleString: String? = "An optional string."
- let forcedString: String = possibleString! // requires an exclamation point
- let assumedString: String! = "An implicitly unwrapped optional string."
- let implicitString: String = assumedString // no need for an exclamation point
您可以將隱式解包的可選對象視為允許在需要時強制打開可選對象的權限。當您使用隱式解包的可選值時,Swift首先嘗試將其用作普通的可選值;如果不能將其用作可選內容,則Swift會強制展開該值。在上面的代碼中,將可選值assumedString
分配給之前,將其強制展開,implicitString
因為implicitString
它具有顯式的非可選類型String
。在下面的代碼中,optionalString
沒有顯式類型,因此是普通的可選。
- let optionalString = assumedString
- // The type of optionalString is "String?" and assumedString isn't force-unwrapped.
如果一個隱式解包的可選nil
變量是,並且您嘗試訪問其包裝值,則會觸發運行時錯誤。結果與將感嘆號放置在不包含值的普通可選內容之后完全相同。
您可以檢查隱式展開的可選是否nil
與檢查普通可選相同:
- if assumedString != nil {
- print(assumedString!)
- }
- // Prints "An implicitly unwrapped optional string."
您還可以使用帶有可選綁定的隱式解包的可選內容,以在單個語句中檢查和解開其值:
- if let definiteString = assumedString {
- print(definiteString)
- }
- // Prints "An implicitly unwrapped optional string."
注意
當變量可能nil
在以后出現時,請不要使用隱式展開的可選。如果需要nil
在變量的生存期內檢查值,請始終使用普通的可選類型。
錯誤處理
您可以使用錯誤處理來響應程序在執行過程中可能遇到的錯誤情況。
與可以使用值的存在或不存在來傳達函數成功或失敗的可選選項相反,錯誤處理使您可以確定失敗的根本原因,並在必要時將錯誤傳播到程序的另一部分。
當函數遇到錯誤條件時,它將引發錯誤。然后,該函數的調用方可以捕獲錯誤並做出適當響應。
- func canThrowAnError() throws {
- // this function may or may not throw an error
- }
函數通過throws
在其聲明中包含關鍵字來表明它可以引發錯誤。當您調用可能引發錯誤的函數時,會將try
關鍵字放在表達式的前面。
Swift會自動將錯誤傳播到當前范圍之外,直到由catch
子句處理為止。
- do {
- try canThrowAnError()
- // no error was thrown
- } catch {
- // an error was thrown
- }
一條do
語句創建一個新的包含范圍,該范圍允許將錯誤傳播到一個或多個catch
子句。
這是一個示例,說明如何使用錯誤處理來響應不同的錯誤情況:
- func makeASandwich() throws {
- // ...
- }
- do {
- try makeASandwich()
- eatASandwich()
- } catch SandwichError.outOfCleanDishes {
- washDishes()
- } catch SandwichError.missingIngredients(let ingredients) {
- buyGroceries(ingredients)
- }
在此示例中,makeASandwich()
如果沒有干凈的盤子或缺少任何配料,該函數將引發錯誤。因為makeASandwich()
會拋出錯誤,所以函數調用被包裝在一個try
表達式中。通過將函數調用包裝在一條do
語句中,拋出的任何錯誤都將傳播到提供的catch
子句中。
如果未引發任何錯誤,eatASandwich()
則調用該函數。如果拋出錯誤並且匹配SandwichError.outOfCleanDishes
大小寫,則將washDishes()
調用該函數。如果引發了一個錯誤並且與SandwichError.missingIngredients
大小寫匹配,則buyGroceries(_:)
使用模式[String]
捕獲的關聯值調用該函數catch
。
錯誤處理中更詳細地介紹了引發,捕獲和傳播錯誤。
斷言和前提條件
斷言和前提條件是在運行時進行的檢查。您可以使用它們來確保在執行任何其他代碼之前滿足基本條件。如果斷言或前提條件中的布爾條件求值為true
,則代碼將照常繼續執行。如果條件的計算結果為false
,則程序的當前狀態無效;否則,結果為0。代碼執行結束,您的應用程序終止。
您可以使用斷言和前提條件來表達您在進行編碼時所做的假設和期望,因此您可以將其包含在代碼中。斷言可幫助您在開發過程中發現錯誤和不正確的假設,前提條件可幫助您檢測生產中的問題。
除了在運行時驗證您的期望之外,斷言和前提條件也成為代碼中文檔的一種有用形式。與上述錯誤處理中討論的錯誤條件不同,斷言和前提條件不用於可恢復或預期的錯誤。由於失敗的斷言或前提條件指示無效的程序狀態,因此無法捕獲失敗的斷言。
使用斷言和前提條件並不能代替以不太可能出現無效條件的方式來設計代碼。但是,使用它們強制執行有效的數據和狀態會使您的應用程序在發生無效狀態時更可預測地終止,並有助於使問題更易於調試。一旦檢測到無效狀態,立即停止執行還有助於限制該無效狀態所造成的損害。
斷言和前提條件之間的區別在於它們的檢查時間:斷言僅在調試版本中進行檢查,而前提條件在調試和生產版本中均進行檢查。在生產版本中,不會評估斷言中的條件。這意味着您可以在開發過程中使用任意數量的斷言,而不會影響生產性能。
斷言調試
您可以通過調用assert(_:_:file:line:)
Swift標准庫中的函數來編寫斷言。如果此條件的結果為,則向此函數傳遞一個表達式,該表達式的計算結果為true
或,false
並顯示一條消息false
。例如:
- let age = -3
- assert(age >= 0, "A person's age can't be less than zero.")
- // This assertion fails because -3 is not >= 0.
在此示例中,如果的值為,即如果的值為非負數,則代碼執行將繼續。如果如上面的代碼中所示,的值為負,則求值為,並且斷言失敗,從而終止應用程序。age >= 0
true
age
age
age >= 0
false
您可以省略斷言消息,例如,當它只是將條件重復為散文時。
- assert(age >= 0)
如果代碼已經檢查了條件,則可以使用該assertionFailure(_:file:line:)
函數指示斷言失敗。例如:
- if age > 10 {
- print("You can ride the roller-coaster or the ferris wheel.")
- } else if age >= 0 {
- print("You can ride the ferris wheel.")
- } else {
- assertionFailure("A person's age can't be less than zero.")
- }
執行先決條件
使用時的條件必須是假的潛力的前提條件,但必須肯定是真的對你的代碼繼續執行。例如,使用前提條件檢查下標是否未超出范圍,或檢查是否已向函數傳遞了有效值。
您可以通過調用precondition(_:_:file:line:)
函數來編寫前提條件。如果此條件的結果為,則向此函數傳遞一個表達式,該表達式的計算結果為true
或,false
並顯示一條消息false
。例如:
- // In the implementation of a subscript...
- precondition(index > 0, "Index must be greater than zero.")
您還可以調用該preconditionFailure(_:file:line:)
函數以指示發生了故障-例如,如果采用了開關的默認情況,但是所有有效輸入數據都應該由開關的其他情況之一處理。
注意
如果您以非檢查模式(-Ounchecked
)進行編譯,則不會檢查前提條件。編譯器假定前提條件始終為真,並相應地優化了代碼。但是,fatalError(_:file:line:)
無論優化設置如何,該功能始終會暫停執行。
fatalError(_:file:line:)
通過編寫fatalError("Unimplemented")
存根實現,可以在原型開發和早期開發過程中使用該函數為尚未實現的功能創建存根。由於致命錯誤永遠不會被優化,這與斷言或前提條件不同,因此可以確保在遇到存根實現時始終停止執行。