類型安全和類型推斷(Type Safety and Type Inference)
- Swift是一個類型安全的語言肖油,所以會在編譯的時候會檢查類型不匹配的錯誤。這么做可以盡可能早的在開發(fā)過程中發(fā)現(xiàn)錯誤反镇。
- 類型檢查幫助避免在不同類型的值的錯誤奋蔚。雖然這樣,但也不意味著必須把每個變量(常量)的類型寫出來联贩。因?yàn)镾wift使用類型推斷來給出合適的類型漫仆。
let meaningOfLife = 42
//meaningOfLife is inferred to be of type Int
當(dāng)不聲明一個浮點(diǎn)型時,默認(rèn)是Double類型泪幌。
let pi = 3.14159
//pi is inferred to be of type Double
let anotherPi = 3 + 0.14159
//anotherPi is also inferred to be of type Double
數(shù)字型的字面值(Numeric Literals)
- 整型的字面可以這么寫:
- 十進(jìn)制:不需要前綴
- 二進(jìn)制:前綴為"0b"
- 八進(jìn)制:前綴為"0o"
- 十六進(jìn)制:前綴為"0x"
以下這些的值都是17
let decimalInteger = 17
let binaryInteger = 0b10001
let octalInteger = 0o21
let hexadecimalInteger = 0x11
-
浮點(diǎn)型的字面可以為十進(jìn)制(沒有前綴)盲厌,也可以為十六進(jìn)制(前綴為"0x")。十進(jìn)制數(shù)用大寫或者小寫的e表示指數(shù)祸泪,十六進(jìn)制數(shù)用大寫或小寫的p表示指數(shù)吗浩。
十進(jìn)制:- 1.25e2 means 1.25 x 10^2, or 125.0.
- 1.25e-2 means 1.25 x 10^(-2), or 0.0125.
十六進(jìn)制:
- 0xFp2 means 15 x 2^2, or 60.0.
- 0xFp-2 means 15 x 2^(-2), or 3.75.
下面這些浮點(diǎn)型的值都是12.1875
let decimalDouble = 12.1875
let exponentDouble = 1.21875e1
let hexadecimalDouble = 0xC.3p0
numeric literals為了更好的閱讀代碼可以包含額外的格式,整型和浮點(diǎn)型都可以使用前綴"0"和下劃線"_"
let paddedDouble = 000123.456
let oneMillion = 1_000_000
let justOverOneMillion = 1_000_000.000_000_1
數(shù)值類型的轉(zhuǎn)換(Numeric Type Conversion)#
- 整型的轉(zhuǎn)換(Integer Conversion)
當(dāng)然没隘,整形的存儲是不能超過類型的范圍的懂扼,那UInt8(0255)和Int8(-128127)為例:
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
當(dāng)兩種數(shù)值不是一個類型的時候是不能進(jìn)行運(yùn)算的,哪怕他們都是“整型”:
let twoThousand: UInt16 = 2_000
let one: UInt8 = 1
let towThousandAndOne = twoThousand + UInt16(one)
//swift的強(qiáng)制轉(zhuǎn)換和OC是不同的升略,swift是將類型放在括號外面微王,而將變量(常量)放在括號里面。
- 整型和浮點(diǎn)型之間的相互轉(zhuǎn)換(Integer and Floating-Point Conversion)
在整型和浮點(diǎn)型之間轉(zhuǎn)換一定要明確:
let three = 3
let pointOneFourOneFiveNine = 0.141459
let pi = Double(three) + pointOneFourOneFiveNine
// pi equals 3.14159, and is inferred to be of type Double
類型的別稱(Type Aliases)
類型的重命名用到的是"typealias"關(guān)鍵字品嚣。
typealias AudioSample = UInt16
//correct
let max: AudioSample = AudioSample.max
//wrong
let max: AudioSample = UInt16.max
布爾型(Boolean)
Swift中的布爾型與C語言和OC都不一樣炕倘,為"Bool",而其值和C語言是一直的翰撑,分別為"true"和"false"罩旋。
因?yàn)閠ype safety的緣故啊央,下面的代碼是錯誤的
let i = 1
if i {
//this example will not compile, and will repot an error
}
所以,這段代碼應(yīng)該這么寫:
let i = 1
if i == 1 {
//this example will compile successfully
}
因?yàn)?i == 1"的返回值是Bool涨醋,所以這段代碼可以執(zhí)行瓜饥。
元組(Tuples)
元組就是一組多個值合成為一個單一的值,而這一組的多個值并不是一定要相同的類型浴骂。
??:
let http404Error = (404, "Not Found")
//http404Error is of type (Int, String)
你可以在創(chuàng)建一個元組的時候任意的排序類型乓土。
你也可以在定義一個元組的時候,將類型分離溯警,??:
let (statusCode, statusMessage) = http404Error
print("The status code is \(statusCode)")
//Prints "The status code is 404"
如果你只需要為元組中的某個元素命名是趣苏,其他的可以用下劃線(_)代替:
let (justTheStatusCode, _) = http404Error
print("The status code is \(justTheStatusCode)")
// Prints "The status code is 404"
你也可以通過訪問元組的索引值來訪問相應(yīng)的元素:
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"
在定義一個元組的時候,就可以為每個元素命名梯轻,這樣就可以直接通過元素名稱來訪問:
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"
可選變量(Optionals)#
在C語言和OC中是沒有optionals的概念的食磕,但在OC中有一個類似的類型就是NSNil。Optionals通俗點(diǎn)講喳挑,就是這個值可能存在彬伦,也可能不存在。舉個??:
let possibleNumber = "123"
let convertedNumber = Int(possibleNumber)
// convertedNumber is inferred to be of type "Int?", or "optional Int"
- nil
在聲明一個變量的時候可以分配一個特殊的值——nil:
var serverResponseCode: Int? = 404
// serverResponseCode contains an actual Int value of 404
serverResponseCode = nil
// serverResponseCode now contains no value
在聲明一個可選變量的時候不賦給初始值伊诵,默認(rèn)為nil(數(shù)值類型的值同樣為nil)单绑。
- 可選綁定(Optional Binding)
可選綁定,如果一個可選變量的值不為nil曹宴,則將值賦給另外一個變量(常量)询张。可選綁定可以用在if和while的判斷條件中浙炼。??:
if let actualNumber = Int(possibleNumber) {
print("\"\(possibleNumber)\" has an integer value of \(actualNumber)")
} else {
print("\"\(possibleNumber)\" could not be converted to an integer")
}
// Prints ""123" has an integer value of 123"
你可以在一個if判斷條件中包含多個可選綁定和"where"子句來進(jìn)行判斷,如果其中有任意一個可選綁定為空(nil)唯袄,或者"where"的返回值為"false"弯屈,整個可選綁定都會不成功:
if let firstNumber = Int("4"), secondNumber = Int("42") where irstNumber < secondNumber {
print("\(firstNumber) < \(secondNumber)")
}
// Prints "4 < 42"
- 隱式解析可選類型(Implicitly Unwrapped Optional)(也不知道是不是叫這個名字)
有些變量在聲明的時候就已經(jīng)有值了,如果還是每次都判斷是否為空就會非常低效恋拷,所以就有了這個Implicity Unwrapped Optional類型资厉,意思就是我聲明的這個變量不為空,用感嘆號表示(!)蔬顾。
下面這個??展示了Optionals和Implicity Unwrapped Optional的區(qū)別:
let possibleString: String? = "An optional string."
let forcedString: String = possibleString! // requires an exclamation mark
let assumedString: String! = "An implicitly unwrapped optional string."
let implicitString: String = assumedString // no need for an exclamation mark
同樣的宴偿,你可以判斷隱式解析可選類型是否為空(nil),也可以進(jìn)行可選綁定诀豁。
??:
if assumedString != nil {
print(assumedString)
}
// Prints "An implicitly unwrapped optional string."
if let definiteString = assumedString {
print(definiteString)
}
// Prints "An implicitly unwrapped optional string."
異常處理(Error Handling)
當(dāng)一個方法遇到錯誤情況窄刘,它就會拋出(throws)一個錯誤。而方法的調(diào)用者就會捕捉(catch)到錯誤信息舷胜,并及時處理娩践。
func canThrowAnError() throws {
//this function may or may not throw an error
}
當(dāng)一個方法可以拋出錯誤的時候在它聲明方法名的時候要包括"throws"關(guān)鍵字。當(dāng)你調(diào)用一個可以拋出錯誤的方法時,在前面用"try"關(guān)鍵字來修飾翻伺。
Swift會自動將錯誤信息從當(dāng)先這個范圍傳遞出去材泄,知道會遇到"catch"子句的時候才會進(jìn)行處理。
do {
try canThrowAnError()
//no error was thrown
} catch {
//an error was thrown
}
"do"狀態(tài)創(chuàng)建了一個新的可以允許錯誤信息傳遞給一個或者多個"catch"子句的包含范圍吨岭。
??:
func makeASandwich() throws {
// ...
}
do {
try makeASandwich()
eatASandwich()
} catch SandwichError.outOfCleanDishes {
washDishes()
} catch SandwichError.missingIngredients(let ingredients) {
buyGroceries(ingredients)
}
上面這個??中拉宗,"makeASandewich()"將會在沒有干凈盤子的時候執(zhí)行"washDishes()"。之所以"makeASandwich()"可以拋出一個錯誤辣辫,是因?yàn)檫@個方法包含了"try"表達(dá)式旦事。如果沒有錯誤拋出,那么"eatASandwich()"這個方法就會執(zhí)行络它。
-
斷言(Assertions)
在某些情況下族檬,如果一個特定的條件不滿足,那么代碼就不會繼續(xù)執(zhí)行化戳。在這些情況下单料,你可以在你的代碼中設(shè)置一個斷言(asserttion)來結(jié)束代碼的執(zhí)行或者提供一個調(diào)試值為空或者不存在的機(jī)會。- 用斷言進(jìn)行調(diào)試(Debug with Assertions)
assertion會在runtime檢查一個Boolean表達(dá)式的值是否為true点楼。字面的意思就是扫尖,一個assertion"斷言"一個表達(dá)式是否為真。如果表達(dá)式的值為true掠廓,那么代碼會照常執(zhí)行换怖,如果表達(dá)式的值為false,代碼執(zhí)行結(jié)束蟀瞧,app會直接終止沉颂。
但你在調(diào)試情況下使用assertions,可以附加一條自己的信息悦污。在Swift標(biāo)準(zhǔn)庫中铸屉,調(diào)用"assert(::file:line:)"方法,這是一個全球變量:
- 用斷言進(jìn)行調(diào)試(Debug with Assertions)
let age = -3
assert(age >= 0, "A person's age cannot be less than zero")
//this causes the assertion to trigger, because age is not >= 0
assertions的信息也可以省略切端。
assert(age >= 0)
- 什么時候使用斷言(When to Use Assertions)
使用assertions首先要確保表達(dá)是的值有可能為false彻坛,但是想要代碼繼續(xù)執(zhí)行的話,值一定為true踏枣。以下幾種情況適用assertions:- 一個整數(shù)下標(biāo)索引值傳到了一個自定義的下標(biāo)實(shí)現(xiàn)昌屉,而值超出了范圍(太小或太大)。
- 給函數(shù)傳入一個值茵瀑,但是非法的值可能導(dǎo)致函數(shù)不能正常執(zhí)行间驮。
- 一個可選值現(xiàn)在為nil,但是代碼需要一個不為nil的值才能成功執(zhí)行马昨。