基礎部分(The Basics)web
1.0 翻譯:numbbbbb, lyuka, JaySurplus 校對:lslxdx編程
2.0 翻譯+校對:xtymichael安全
2.1 翻譯:Prayer 校對:shanks,overtrue 本頁包含內容:服務器
常量和變量 聲明常量和變量 類型標註 常量和變量的命名 輸出常量和變量 註釋 分號 整數 整數範圍 Int UInt 浮點數 類型安全和類型推斷 數值型字面量 數值型類型轉換 整數轉換 數整數和浮點數轉換 類型別名 布爾值 元組 可選 nil if 語句以及強制解析 可選綁定 隱式解析可選類型 錯誤處理 斷言 Swift 是一門開發 iOS, OS X 和 watchOS 應用的新語言。然而,若是你有 C 或者 Objective-C 開發經驗的話,你會發現 Swift 的不少內容都是你熟悉的。數據結構
Swift 包含了 C 和 Objective-C 上全部基礎數據類型,Int表示整型值;Double和Float表示浮點型值;Bool是布爾型值;String是文本型數據。Swift 還提供了三個基本的集合類型,Array,Set和Dictionary,詳見集合類型。架構
就像 C 語言同樣,Swift 使用變量來進行存儲並經過變量名來關聯值。在 Swift 中,普遍的使用着值不可變的變量,它們就是常量,並且比 C 語言的常量更強大。在 Swift 中,若是你要處理的值不須要改變,那使用常量可讓你的代碼更加安全而且更清晰地表達你的意圖。app
除了咱們熟悉的類型,Swift 還增長了 Objective-C 中沒有的高階數據類型好比元組(Tuple)。元組可讓你建立或者傳遞一組數據,好比做爲函數的返回值時,你能夠用一個元組能夠返回多個值。less
Swift 還增長了可選(Optional)類型,用於處理值缺失的狀況。可選表示「那兒有一個值,而且它等於 x 」或者「那兒沒有值」。可選有點像在 Objective-C 中使用nil,可是它能夠用在任何類型上,不只僅是類。可選類型比 Objective-C 中的nil指針更加安全也更具表現力,它是 Swift 許多強大特性的重要組成部分。編程語言
Swift 是一門類型安全的語言,可選類型就是一個很好的例子。Swift 可讓你清楚地知道值的類型。若是你的代碼指望獲得一個String,類型安全會阻止你不當心傳入一個Int。你能夠在開發階段儘早發現並修正錯誤。函數
常量和變量 常量和變量把一個名字(好比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關鍵字將它聲明爲常量。只將須要改變的值聲明爲變量。
類型標註
當你聲明常量或者變量的時候能夠加上類型標註(type annotation),說明常量或者變量中要存儲的值的類型。若是要添加類型標註,須要在常量或者變量名後面加上一個冒號和空格,而後加上類型名稱。
這個例子給welcomeMessage變量添加了類型標註,表示這個變量能夠存儲String類型的值:
var welcomeMessage: String 聲明中的冒號表明着「是...類型」,因此這行代碼能夠被理解爲:
「聲明一個類型爲String,名字爲welcomeMessage的變量。」
「類型爲String」的意思是「能夠存儲任意String類型的值。」
welcomeMessage變量如今能夠被設置成任意字符串:
welcomeMessage = "Hello" 你能夠在一行中定義多個一樣類型的變量,用逗號分割,並在最後一個變量名以後添加類型標註:
var red, green, blue: Double 注意: 通常來講你不多須要寫類型標註。若是你在聲明常量或者變量的時候賦了一個初始值,Swift能夠推斷出這個常量或者變量的類型,請參考類型安全和類型推斷。在上面的例子中,沒有給welcomeMessage賦初始值,因此變量welcomeMessage的類型是經過一個類型標註指定的,而不是經過初始值推斷的。
常量和變量的命名
你能夠用任何你喜歡的字符做爲常量和變量名,包括 Unicode 字符:
let π = 3.14159 let 你好 = "你好世界" let 🐶🐮 = "dogcow" 常量與變量名不能包含數學符號,箭頭,保留的(或者非法的)Unicode 碼位,連線與製表符。也不能以數字開頭,可是能夠在常量與變量名的其餘地方包含數字。
一旦你將常量或者變量聲明爲肯定的類型,你就不能使用相同的名字再次進行聲明,或者改變其存儲的值的類型。同時,你也不能將常量與變量進行互轉。
注意: 若是你須要使用與Swift保留關鍵字相同的名稱做爲常量或者變量名,你可使用反引號(`)將關鍵字包圍的方式將其做爲名字使用。不管如何,你應當避免使用關鍵字做爲常量或變量名,除非你別無選擇。 你能夠更改現有的變量值爲其餘同類型的值,在下面的例子中,friendlyWelcome的值從"Hello!"改成了"Bonjour!":
var friendlyWelcome = "Hello!" friendlyWelcome = "Bonjour!" // friendlyWelcome 如今是 "Bonjour!" 與變量不一樣,常量的值一旦被肯定就不能更改了。嘗試這樣作會致使編譯時報錯:
let languageName = "Swift" languageName = "Swift++" // 這會報編譯時錯誤 - languageName 不可改變
輸出常量和變量
你能夠用print(_:separator:terminator:)函數來輸出當前常量或變量的值:
print(friendlyWelcome) // 輸出 "Bonjour!" print(:separator:terminator:)是一個用來輸出一個或多個值到適當輸出區的全局函數。若是你用 Xcode,print(:separator:terminator:)將會輸出內容到「console」面板上。separator和terminator參數具備默認值,所以你調用這個函數的時候能夠忽略它們。默認狀況下,該函數經過添加換行符來結束當前行。若是不想換行,能夠傳遞一個空字符串給terminator參數--例如,print(someValue, terminator:"")。關於參數默認值的更多信息,請參考默認參數值。
Swift 用字符串插值(string interpolation)的方式把常量名或者變量名當作佔位符加入到長字符串中,Swift 會用當前常量或變量的值替換這些佔位符。將常量或變量名放入圓括號中,並在開括號前使用反斜槓將其轉義:
print("The current value of friendlyWelcome is (friendlyWelcome)") // 輸出 "The current value of friendlyWelcome is Bonjour! 注意: 字符串插值全部可用的選項,請參考字符串插值。
註釋 請將你的代碼中的非執行文本註釋成提示或者筆記以方便你未來閱讀。Swift 的編譯器將會在編譯代碼時自動忽略掉註釋部分。
Swift 中的註釋與 C 語言的註釋很是類似。單行註釋以雙正斜槓(//)做爲起始標記:
// 這是一個註釋 你也能夠進行多行註釋,其起始標記爲單個正斜槓後跟隨一個星號(/),終止標記爲一個星號後跟隨單個正斜槓(/):
/* 這是一個, 多行註釋 */ 與 C 語言多行註釋不一樣,Swift 的多行註釋能夠嵌套在其它的多行註釋之中。你能夠先生成一個多行註釋塊,而後在這個註釋塊之中再嵌套成第二個多行註釋。終止註釋時先插入第二個註釋塊的終止標記,而後再插入第一個註釋塊的終止標記:
/* 這是第一個多行註釋的開頭 /* 這是第二個被嵌套的多行註釋 */ 這是第一個多行註釋的結尾 */ 經過運用嵌套多行註釋,你能夠快速方便的註釋掉一大段代碼,即便這段代碼之中已經含有了多行註釋塊。
分號 與其餘大部分編程語言不一樣,Swift 並不強制要求你在每條語句的結尾處使用分號(;),固然,你也能夠按照你本身的習慣添加分號。有一種狀況下必需要用分號,即你打算在同一行內寫多條獨立的語句:
let cat = "🐱"; print(cat) // 輸出 "🐱"
整數 整數就是沒有小數部分的數字,好比42和-23。整數能夠是有符號(正、負、零)或者無符號(正、零)。
Swift 提供了8,16,32和64位的有符號和無符號整數類型。這些整數類型和 C 語言的命名方式很像,好比8位無符號整數類型是UInt8,32位有符號整數類型是Int32。就像 Swift 的其餘類型同樣,整數類型採用大寫命名法。
整數範圍
你能夠訪問不一樣整數類型的min和max屬性來獲取對應類型的最小值和最大值:
let minValue = UInt8.min // minValue 爲 0,是 UInt8 類型 let maxValue = UInt8.max // maxValue 爲 255,是 UInt8 類型 min和max所傳回值的類型,正是其所對的整數類型(如上例UInt8, 所傳回的類型是UInt8),可用在表達式中相同類型值旁。
Int
通常來講,你不須要專門指定整數的長度。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能夠提升代碼的可複用性,避免不一樣類型數字之間的轉換,而且匹配數字的類型推斷,請參考類型安全和類型推斷。
浮點數 浮點數是有小數部分的數字,好比3.14159,0.1和-273.15。
浮點類型比整數類型表示的範圍更大,能夠存儲比Int類型更大或者更小的數字。Swift 提供了兩種有符號浮點數類型:
Double表示64位浮點數。當你須要存儲很大或者很高精度的浮點數時請使用此類型。 Float表示32位浮點數。精度要求不高的話可使用此類型。 注意: Double精確度很高,至少有15位數字,而Float只有6位數字。選擇哪一個類型取決於你的代碼須要處理的值的範圍。
類型安全和類型推斷 Swift 是一個類型安全(type safe)的語言。類型安全的語言可讓你清楚地知道代碼要處理的值的類型。若是你的代碼須要一個String,你絕對不可能不當心傳進去一個Int。
因爲 Swift 是類型安全的,因此它會在編譯你的代碼時進行類型檢查(type checks),並把不匹配的類型標記爲錯誤。這可讓你在開發的時候儘早發現並修復錯誤。
當你要處理不一樣類型的值時,類型檢查能夠幫你避免錯誤。然而,這並非說你每次聲明常量和變量的時候都須要顯式指定類型。若是你沒有顯式指定類型,Swift 會使用類型推斷(type inference)來選擇合適的類型。有了類型推斷,編譯器能夠在編譯代碼的時候自動推斷出表達式的類型。原理很簡單,只要檢查你賦的值便可。
由於有類型推斷,和 C 或者 Objective-C 比起來 Swift 不多須要聲明類型。常量和變量雖然須要明確類型,可是大部分工做並不須要你本身來完成。
當你聲明常量或者變量並賦初值的時候類型推斷很是有用。當你在聲明常量或者變量的時候賦給它們一個字面量(literal value 或 literal)便可觸發類型推斷。(字面量就是會直接出如今你代碼中的值,好比42和3.14159。)
例如,若是你給一個新常量賦值42而且沒有標明類型,Swift 能夠推斷出常量類型是Int,由於你給它賦的初始值看起來像一個整數:
let meaningOfLife = 42 // meaningOfLife 會被推測爲 Int 類型 同理,若是你沒有給浮點字面量標明類型,Swift 會推斷你想要的是Double:
let pi = 3.14159 // pi 會被推測爲 Double 類型 當推斷浮點數的類型時,Swift 老是會選擇Double而不是Float。
若是表達式中同時出現了整數和浮點數,會被推斷爲Double類型:
let anotherPi = 3 + 0.14159 // anotherPi 會被推測爲 Double 類型 原始值3沒有顯式聲明類型,而表達式中出現了一個浮點字面量,因此表達式會被推斷爲Double類型。
數值型字面量 整數字面量能夠被寫做:
一個十進制數,沒有前綴 一個二進制數,前綴是0b 一個八進制數,前綴是0o 一個十六進制數,前綴是0x 下面的全部整數字面量的十進制值都是17:
let decimalInteger = 17 let binaryInteger = 0b10001 // 二進制的17 let octalInteger = 0o21 // 八進制的17 let hexadecimalInteger = 0x11 // 十六進制的17 浮點字面量能夠是十進制(沒有前綴)或者是十六進制(前綴是0x)。小數點兩邊必須有至少一個十進制數字(或者是十六進制的數字)。十進制浮點數也能夠有一個可選的指數(exponent),經過大寫或者小寫的 e 來指定;十六進制浮點數必須有一個指數,經過大寫或者小寫的 p 來指定。
若是一個十進制數的指數爲exp,那這個數至關於基數和10^exp的乘積:
1.25e2 表示 1.25 × 10^2,等於 125.0。 1.25e-2 表示 1.25 × 10^-2,等於 0.0125。 若是一個十六進制數的指數爲exp,那這個數至關於基數和2^exp的乘積:
0xFp2 表示 15 × 2^2,等於 60.0。 0xFp-2 表示 15 × 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 類型不能存儲負數,因此會報錯 let tooBig: Int8 = Int8.max + 1 // Int8 類型不能存儲超過最大值的數,因此會報錯 因爲每種整數類型均可以存儲不一樣範圍的值,因此你必須根據不一樣狀況選擇性使用數值型類型轉換。這種選擇性使用的方式,能夠預防隱式轉換的錯誤並讓你的代碼中的類型轉換意圖變得清晰。
要將一種數字類型轉換成另外一種,你要用當前值來初始化一個指望類型的新數字,這個數字的類型就是你的目標類型。在下面的例子中,常量twoThousand是UInt16類型,然而常量one是UInt8類型。它們不能直接相加,由於它們類型不一樣。因此要調用UInt16(one)來建立一個新的UInt16數字並用one的值來初始化,而後使用這個新數字來計算:
let twoThousand: UInt16 = 2_000 let one: UInt8 = 1 let twoThousandAndOne = twoThousand + UInt16(one) 如今兩個數字的類型都是UInt16,能夠進行相加。目標常量twoThousandAndOne的類型被推斷爲UInt16,由於它是兩個UInt16值的和。
SomeType(ofInitialValue)是調用 Swift 構造器並傳入一個初始值的默認方法。在語言內部,UInt16有一個構造器,能夠接受一個UInt8類型的值,因此這個構造器能夠用現有的UInt8來建立一個新的UInt16。注意,你並不能傳入任意類型的值,只能傳入UInt16內部有對應構造器的值。不過你能夠擴展示有的類型來讓它能夠接收其餘類型的值(包括自定義類型),請參考擴展。
整數和浮點數轉換
整數和浮點數的轉換必須顯式指定類型:
let three = 3 let pointOneFourOneFiveNine = 0.14159 let pi = Double(three) + pointOneFourOneFiveNine // pi 等於 3.14159,因此被推測爲 Double 類型 這個例子中,常量three的值被用來建立一個Double類型的值,因此加號兩邊的數類型須相同。若是不進行轉換,二者沒法相加。
浮點數到整數的反向轉換一樣行,整數類型能夠用Double或者Float類型來初始化:
let integerPi = Int(pi) // integerPi 等於 3,因此被推測爲 Int 類型 當用這種方式來初始化一個新的整數值時,浮點值會被截斷。也就是說4.75會變成4,-3.9會變成-3。
注意: 結合數字類常量和變量不一樣於結合數字類字面量。字面量3能夠直接和字面量0.14159相加,由於數字字面量自己沒有明確的類型。它們的類型只在編譯器須要求值的時候被推測。
類型別名 類型別名(type aliases)就是給現有類型定義另外一個名字。你可使用typealias關鍵字來定義類型別名。
當你想要給現有類型起一個更有意義的名字時,類型別名很是有用。假設你正在處理特定長度的外部資源的數據:
typealias AudioSample = UInt16 定義了一個類型別名以後,你能夠在任何使用原始名的地方使用別名:
var maxAmplitudeFound = AudioSample.min // maxAmplitudeFound 如今是 0 本例中,AudioSample被定義爲UInt16的一個別名。由於它是別名,AudioSample.min其實是UInt16.min,因此會給maxAmplitudeFound賦一個初值0。
布爾值 Swift 有一個基本的布爾(Boolean)類型,叫作Bool。布爾值指邏輯上的值,由於它們只能是真或者假。Swift 有兩個布爾常量,true和false:
let orangesAreOrange = true let turnipsAreDelicious = false orangesAreOrange和turnipsAreDelicious的類型會被推斷爲Bool,由於它們的初值是布爾字面量。就像以前提到的Int和Double同樣,若是你建立變量的時候給它們賦值true或者false,那你不須要將常量或者變量聲明爲Bool類型。初始化常量或者變量的時候若是所賦的值類型已知,就能夠觸發類型推斷,這讓 Swift 代碼更加簡潔而且可讀性更高。
當你編寫條件語句好比if語句的時候,布爾值很是有用:
if turnipsAreDelicious { print("Mmm, tasty turnips!") } else { print("Eww, turnips are horrible.") } // 輸出 "Eww, turnips are horrible." 條件語句,例如if,請參考控制流。
若是你在須要使用Bool類型的地方使用了非布爾值,Swift 的類型安全機制會報錯。下面的例子會報告一個編譯時錯誤:
let i = 1 if i { // 這個例子不會經過編譯,會報錯 } 然而,下面的例子是合法的:
let i = 1 if i == 1 { // 這個例子會編譯成功 } i == 1的比較結果是Bool類型,因此第二個例子能夠經過類型檢查。相似i == 1這樣的比較,請參考基本操做符。
和 Swift 中的其餘類型安全的例子同樣,這個方法能夠避免錯誤並保證這塊代碼的意圖老是清晰的。
元組 元組(tuples)把多個值組合成一個複合值。元組內的值能夠是任意類型,並不要求是相同類型。
下面這個例子中,(404, "Not Found")是一個描述 HTTP 狀態碼(HTTP status code)的元組。HTTP 狀態碼是當你請求網頁的時候 web 服務器返回的一個特殊值。若是你請求的網頁不存在就會返回一個404 Not Found狀態碼。
let http404Error = (404, "Not Found") // http404Error 的類型是 (Int, String),值是 (404, "Not Found") (404, "Not Found")元組把一個Int值和一個String值組合起來表示 HTTP 狀態碼的兩個部分:一個數字和一我的類可讀的描述。這個元組能夠被描述爲「一個類型爲(Int, String)的元組」。
你能夠把任意順序的類型組合成一個元組,這個元組能夠包含全部類型。只要你想,你能夠建立一個類型爲(Int, Int, Int)或者(String, Bool)或者其餘任何你想要的組合的元組。
你能夠將一個元組的內容分解(decompose)成單獨的常量和變量,而後你就能夠正常使用它們了:
let (statusCode, statusMessage) = http404Error print("The status code is (statusCode)") // 輸出 "The status code is 404" print("The status message is (statusMessage)") // 輸出 "The status message is Not Found" 若是你只須要一部分元組值,分解的時候能夠把要忽略的部分用下劃線(_)標記:
let (justTheStatusCode, _) = http404Error print("The status code is (justTheStatusCode)") // 輸出 "The status code is 404" 此外,你還能夠經過下標來訪問元組中的單個元素,下標從零開始:
print("The status code is (http404Error.0)") // 輸出 "The status code is 404" print("The status message is (http404Error.1)") // 輸出 "The status message is Not Found" 你能夠在定義元組的時候給單個元素命名:
let http200Status = (statusCode: 200, description: "OK") 給元組中的元素命名後,你能夠經過名字來獲取這些元素的值:
print("The status code is (http200Status.statusCode)") // 輸出 "The status code is 200" print("The status message is (http200Status.description)") // 輸出 "The status message is OK" 做爲函數返回值時,元組很是有用。一個用來獲取網頁的函數可能會返回一個(Int, String)元組來描述是否獲取成功。和只能返回一個類型的值比較起來,一個包含兩個不一樣類型值的元組可讓函數的返回信息更有用。請參考函數參數與返回值。
注意: 元組在臨時組織值的時候頗有用,可是並不適合建立複雜的數據結構。若是你的數據結構並非臨時使用,請使用類或者結構體而不是元組。請參考類和結構體。
可選類型 使用可選類型(optionals)來處理值可能缺失的狀況。可選類型表示:
有值,等於 x 或者
沒有值 注意: C 和 Objective-C 中並無可選類型這個概念。最接近的是 Objective-C 中的一個特性,一個方法要不返回一個對象要不返回nil,nil表示「缺乏一個合法的對象」。然而,這隻對對象起做用——對於結構體,基本的 C 類型或者枚舉類型不起做用。對於這些類型,Objective-C 方法通常會返回一個特殊值(好比NSNotFound)來暗示值缺失。這種方法假設方法的調用者知道並記得對特殊值進行判斷。然而,Swift 的可選類型可讓你暗示_任意類型_的值缺失,並不須要一個特殊值。 來看一個例子。Swift 的String類型有一種構造器,做用是將一個String值轉換成一個Int值。然而,並非全部的字符串均可以轉換成一個整數。字符串"123"能夠被轉換成數字123,可是字符串"hello, world"不行。
下面的例子使用這種構造器來嘗試將一個String轉換成Int:
let possibleNumber = "123" let convertedNumber = Int(possibleNumber) // convertedNumber 被推測爲類型 "Int?", 或者類型 "optional Int" 由於該構造器可能會失敗,因此它返回一個可選類型(optional)Int,而不是一個Int。一個可選的Int被寫做Int?而不是Int。問號暗示包含的值是可選類型,也就是說可能包含Int值也可能不包含值。(不能包含其餘任何值好比Bool值或者String值。只能是Int或者什麼都沒有。)
nil
你能夠給可選變量賦值爲nil來表示它沒有值:
var serverResponseCode: Int? = 404 // serverResponseCode 包含一個可選的 Int 值 404 serverResponseCode = nil // serverResponseCode 如今不包含值 注意: nil不能用於非可選的常量和變量。若是你的代碼中有常量或者變量須要處理值缺失的狀況,請把它們聲明成對應的可選類型。 若是你聲明一個可選常量或者變量可是沒有賦值,它們會自動被設置爲nil:
var surveyAnswer: String? // surveyAnswer 被自動設置爲 nil 注意: Swift 的nil和 Objective-C 中的nil並不同。在 Objective-C 中,nil是一個指向不存在對象的指針。在 Swift 中,nil不是指針——它是一個肯定的值,用來表示值缺失。任何類型的可選狀態均可以被設置爲nil,不僅是對象類型。
if 語句以及強制解析
你可使用if語句和nil比較來判斷一個可選值是否包含值。你可使用「相等」(==)或「不等」(!=)來執行比較。
若是可選類型有值,它將不等於nil:
if convertedNumber != nil { print("convertedNumber contains some integer value.") } // 輸出 "convertedNumber contains some integer value." 當你肯定可選類型確實包含值以後,你能夠在可選的名字後面加一個感嘆號(!)來獲取值。這個驚歎號表示「我知道這個可選有值,請使用它。」這被稱爲可選值的強制解析(forced unwrapping):
if convertedNumber != nil { print("convertedNumber has an integer value of (convertedNumber!).") } // 輸出 "convertedNumber has an integer value of 123." 更多關於if語句的內容,請參考控制流。
注意: 使用!來獲取一個不存在的可選值會致使運行時錯誤。使用!來強制解析值以前,必定要肯定可選包含一個非nil的值。
可選綁定
使用可選綁定(optional binding)來判斷可選類型是否包含值,若是包含就把值賦給一個臨時常量或者變量。可選綁定能夠用在if和while語句中,這條語句不只能夠用來判斷可選類型中是否有值,同時能夠將可選類型中的值賦給一個常量或者變量。if和while語句,請參考控制流。
像下面這樣在if語句中寫一個可選綁定:
if let constantName = someOptional { statements } 你能夠像上面這樣使用可選綁定來重寫possibleNumber這個例子:
if let actualNumber = Int(possibleNumber) { print("'(possibleNumber)' has an integer value of (actualNumber)") } else { print("'(possibleNumber)' could not be converted to an integer") } // 輸出 "'123' has an integer value of 123" 這段代碼能夠被理解爲:
「若是Int(possibleNumber)返回的可選Int包含一個值,建立一個叫作actualNumber的新常量並將可選包含的值賦給它。」
若是轉換成功,actualNumber常量能夠在if語句的第一個分支中使用。它已經被可選類型 包含的 值初始化過,因此不須要再使用!後綴來獲取它的值。在這個例子中,actualNumber只被用來輸出轉換結果。
你能夠在可選綁定中使用常量和變量。若是你想在if語句的第一個分支中操做actualNumber的值,你能夠改爲if var actualNumber,這樣可選類型包含的值就會被賦給一個變量而很是量。
你能夠包含多個可選綁定在if語句中,並使用where子句作布爾值判斷。
if let firstNumber = Int("4"), secondNumber = Int("42") where firstNumber < secondNumber { print("(firstNumber) < (secondNumber)") } // prints "4 < 42"
隱式解析可選類型
如上所述,可選類型暗示了常量或者變量能夠「沒有值」。可選能夠經過if語句來判斷是否有值,若是有值的話能夠經過可選綁定來解析值。
有時候在程序架構中,第一次被賦值以後,能夠肯定一個可選類型_總會_有值。在這種狀況下,每次都要判斷和解析可選值是很是低效的,由於能夠肯定它總會有值。
這種類型的可選狀態被定義爲隱式解析可選類型(implicitly unwrapped optionals)。把想要用做可選的類型的後面的問號(String?)改爲感嘆號(String!)來聲明一個隱式解析可選類型。
當可選類型被第一次賦值以後就能夠肯定以後一直有值的時候,隱式解析可選類型很是有用。隱式解析可選類型主要被用在 Swift 中類的構造過程當中,請參考無主引用以及隱式解析可選屬性。
一個隱式解析可選類型其實就是一個普通的可選類型,可是能夠被當作非可選類型來使用,並不須要每次都使用解析來獲取可選值。下面的例子展現了可選類型String和隱式解析可選類型String之間的區別:
let possibleString: String? = "An optional string." let forcedString: String = possibleString! // 須要驚歎號來獲取值
let assumedString: String! = "An implicitly unwrapped optional string." let implicitString: String = assumedString // 不須要感嘆號 你能夠把隱式解析可選類型當作一個能夠自動解析的可選類型。你要作的只是聲明的時候把感嘆號放到類型的結尾,而不是每次取值的可選名字的結尾。
注意: 若是你在隱式解析可選類型沒有值的時候嘗試取值,會觸發運行時錯誤。和你在沒有值的普通可選類型後面加一個驚歎號同樣。 你仍然能夠把隱式解析可選類型當作普通可選類型來判斷它是否包含值:
if assumedString != nil { print(assumedString) } // 輸出 "An implicitly unwrapped optional string." 你也能夠在可選綁定中使用隱式解析可選類型來檢查並解析它的值:
if let definiteString = assumedString { print(definiteString) } // 輸出 "An implicitly unwrapped optional string." 注意: 若是一個變量以後可能變成nil的話請不要使用隱式解析可選類型。若是你須要在變量的生命週期中判斷是不是nil的話,請使用普通可選類型。
錯誤處理 你可使用錯誤處理(error handling)來應對程序執行中可能會遇到的錯誤條件。
相對於可選中運用值的存在與缺失來表達函數的成功與失敗,錯誤處理能夠推斷失敗的緣由,並傳播至程序的其餘部分。
當一個函數遇到錯誤條件,它能報錯。調用函數的地方能拋出錯誤消息併合理處理。
func canThrowAnError() throws { // 這個函數有可能拋出錯誤 } 一個函數能夠經過在聲明中添加throws關鍵詞來拋出錯誤消息。當你的函數能拋出錯誤消息時, 你應該在表達式中前置try關鍵詞。
do { try canThrowAnError() // 沒有錯誤消息拋出 } catch { // 有一個錯誤消息拋出 } 一個do語句建立了一個新的包含做用域,使得錯誤能被傳播到一個或多個catch從句。
這裏有一個錯誤處理如何用來應對不一樣錯誤條件的例子。
func makeASandwich() throws { // ... }
do { try makeASandwich() eatASandwich() } catch Error.OutOfCleanDishes { washDishes() } catch Error.MissingIngredients(let ingredients) { buyGroceries(ingredients) } 在此例中,makeASandwich()(作一個三明治)函數會拋出一個錯誤消息若是沒有乾淨的盤子或者某個原料缺失。由於makeASandwich()拋出錯誤,函數調用被包裹在try表達式中。將函數包裹在一個do語句中,任何被拋出的錯誤會被傳播到提供的catch從句中。
若是沒有錯誤被拋出, eatASandwich()函數會被調用。若是一個匹配Error.OutOfCleanDishes的錯誤被拋出,washDishes函數會被調用。若是一個匹配Error.MissingIngredients的錯誤被拋出,buyGroceries(_:)函數會隨着被catch所捕捉到的關聯值[String]被調用。
拋出,捕捉,以及傳播錯誤會在錯誤處理章節詳細說明。
斷言 可選類型可讓你判斷值是否存在,你能夠在代碼中優雅地處理值缺失的狀況。然而,在某些狀況下,若是值缺失或者值並不知足特定的條件,你的代碼可能沒辦法繼續執行。這時,你能夠在你的代碼中觸發一個斷言(assertion)來結束代碼運行並經過調試來找到值缺失的緣由。
使用斷言進行調試
斷言會在運行時判斷一個邏輯條件是否爲true。從字面意思來講,斷言「斷言」一個條件是否爲真。你可使用斷言來保證在運行其餘代碼以前,某些重要的條件已經被知足。若是條件判斷爲true,代碼運行會繼續進行;若是條件判斷爲false,代碼執行結束,你的應用被終止。
若是你的代碼在調試環境下觸發了一個斷言,好比你在 Xcode 中構建並運行一個應用,你能夠清楚地看到不合法的狀態發生在哪裏並檢查斷言被觸發時你的應用的狀態。此外,斷言容許你附加一條調試信息。
你可使用全局assert(_:_file:line:)函數來寫一個斷言。向這個函數傳入一個結果爲true或者false的表達式以及一條信息,當表達式的結果爲false的時候這條信息會被顯示:
let age = -3 assert(age >= 0, "A person's age cannot be less than zero") // 由於 age < 0,因此斷言會觸發 在這個例子中,只有age >= 0爲true的時候,即age的值非負的時候,代碼纔會繼續執行。若是age的值是負數,就像代碼中那樣,age >= 0爲false,斷言被觸發,終止應用。
若是不須要斷言信息,能夠省略,就像這樣:
assert(age >= 0) 注意: 當代碼使用優化編譯的時候,斷言將會被禁用,例如在 Xcode 中,使用默認的 target Release 配置選項來 build 時,斷言會被禁用。 什麼時候使用斷言
當條件可能爲假時使用斷言,可是最終必定要_保證_條件爲真,這樣你的代碼才能繼續運行。斷言的適用情景:
整數類型的下標索引被傳入一個自定義下標腳本實現,可是下標索引值可能過小或者太大。 須要給函數傳入一個值,可是非法的值可能致使函數不能正常執行。 一個可選值如今是nil,可是後面的代碼運行須要一個非nil值。 請參考下標腳本和函數。
注意: 斷言可能致使你的應用終止運行,因此你應當仔細設計你的代碼來讓非法條件不會出現。然而,在你的應用發佈以前,有時候非法條件可能出現,這時使用斷言能夠快速發現問題。