Swift 120 分鐘入門教程

Hello Word

在屏幕上打印“Hello, world”,可以用一行代碼實現(xiàn):

print("Hello, world")

你不需要為了輸入輸出或者字符串處理導(dǎo)入一個單獨的庫,你也不需要main函數(shù),你同樣不需要在每個語句結(jié)尾寫上分號。

數(shù)據(jù)類型

Swift 包含了以下基礎(chǔ)數(shù)據(jù)類型:Int 表示整型;DoubleFloat 表示浮點型;Bool 表示布爾;String 表示字符串。Swift 還提供了三個基本的集合類型,Array 數(shù)組,Set 集合和 Dictionary 字典。

Swift 還增加了高階數(shù)據(jù)類型比如元組(Tuple)。元組可以讓你創(chuàng)建或者傳遞一組數(shù)據(jù),比如作為函數(shù)的返回值時,你可以用一個元組可以返回多個值。

Swift 還增加了可選(Optional)類型,用于處理值缺失的情況??蛇x表示“那兒有一個值,并且它等于 x ”或者“那兒沒有值”??蛇x有點像在 Objective-C 中使用nil,但是它可以用在任何類型上,不僅僅是類??蛇x類型比 Objective-C 中的nil指針更加安全也更具表現(xiàn)力,它是 Swift 許多強(qiáng)大特性的重要組成部分。

非可選類型,要么賦值,要么不賦值(不賦值的話,默認(rèn)不會等于nil);換句話說,非可選類型永遠(yuǎn)不能為 nil

可以在類型后面加?聲明可選類型。調(diào)用時它可能有值,也可能是nil,可以用變量!的形式保證變量有值。

可以在類型后面加!聲明可選類型。調(diào)用時它可能有值,也可能是nil,區(qū)別于上面,直接用變量的形式已經(jīng)保證變量有值了。

你可以使用可選的(Optional)元組反映整個元組可以是 nil 的情況。你可以通過在元組類型的右括號后放置一個問號來定義一個可選元組,例如 (Int,Int)?(String,Int,Bool)?

可選元組類型如(Int,Int)?與元組包含可選屬性如(Int?,Int?)是不同的??蛇x的元組類型,整個數(shù)組是可選的,而不只是元組中的每個元素值。

nil

你可以給可選變量賦值為nil來表示它沒有值

聲明常量和變量

let來聲明常量,用var來聲明變量。

類型標(biāo)注

當(dāng)你聲明常量或者變量的時候可以加上類型標(biāo)注(type annotation),說明常量或者變量中要存儲的值的類型。

使用 :加空格類型名在變量或常量名之后就可以完成類型注解。

注釋

單行注釋:

// 這是一個注釋

多行注釋:

/* 這是一個,
多行注釋 */

多行注釋可以嵌套:

/* 這是第一個多行注釋的開頭
/* 這是第二個被嵌套的多行注釋 */
這是第一個多行注釋的結(jié)尾 */

類型別名

類型別名(type aliases)就是給現(xiàn)有類型定義另一個名字。

你可以使用typealias關(guān)鍵字像使用普通的賦值語句一樣,將某個已經(jīng)存在的類型賦值為新的名字。

typealias 是單一的,不能將整個泛型類型進(jìn)行重命名。只有泛型類型的確定性得到保證后,我們才可以重命名。

基本運算符(Basic Operators)

賦值運算符 =

算術(shù)運算符,基本的四則算術(shù)運算:

  • 加法(+
  • 減法(-
  • 乘法(*
  • 除法(/

求余運算符 a % b

自增 ++ 和自減 --

一元負(fù)號 -

一元正號 +

復(fù)合賦值

組合加運算 +=

比較運算符

  • 等于(a == b
  • 不等于(a != b
  • 大于(a > b
  • 小于(a < b
  • 大于等于(a >= b
  • 小于等于(a <= b

三目運算符

原型是 問題 ? 答案1 : 答案2

空合運算符

空合運算符 a ?? b

空合并運算符是對以下代碼的簡短表達(dá)方法

a != nil ? a! : b

區(qū)間運算符

閉區(qū)間運算符 a...b

半開區(qū)間 a..<b

邏輯運算

  • 邏輯非(!a
  • 邏輯與(a && b
  • 邏輯或(a || b

字符串和字符

String 是有序的 Character 類型的值的集合。

字符串是值拷貝,而非引用。

集合類型 (Collection Types)

Swift 語言提供ArraysSetsDictionaries三種基本的集合類型用來存儲集合數(shù)據(jù)。數(shù)組是有序數(shù)據(jù)的集,集合是無序無重復(fù)數(shù)據(jù)的集,字典是無序的鍵值對的集。

  1. 可以用 Array<T> 也可以用 [T] 這樣的簡單語法創(chuàng)建一個數(shù)組。

創(chuàng)建一個空數(shù)組

var someInts = [Int]()

創(chuàng)建一個帶有默認(rèn)值的數(shù)組

var threeDoubles = [Double](count: 3, repeatedValue:0.0)
  1. Swift中的Set類型被寫為Set<T>, 這里的T表示Set中允許存儲的類型,和數(shù)組不同的是,集合沒有等價的簡化形式。

  2. Swift 的字典使用Dictionary<Key, Value>定義,其中Key是字典中鍵的數(shù)據(jù)類型,Value是字典中對應(yīng)于這些鍵所存儲值的數(shù)據(jù)類型。也可以用[Key: Value]這樣快捷的形式去創(chuàng)建一個字典類型。

控制流

for...in...for initialization; condition; increment { statements }

while condition { statements }repeat { statements } while condition

ifswitch

在 Swift 中,當(dāng)匹配的 case 分支中的代碼執(zhí)行完畢后,程序會終止switch語句,而不會繼續(xù)執(zhí)行下一個 case 分支。這也就是說,不需要在 case 分支中顯式地使用break語句。這使得switch語句更安全、更易用,也避免了因忘記寫break語句而產(chǎn)生的錯誤。

Swift 有四種控制轉(zhuǎn)移語句。

  • continue
  • break
  • fallthrough
  • return
  • throw

強(qiáng)制解包:可以使用 if 語句來檢測一個可選類型是否包含一個特定的值,如果一個可選類型確實包含一個值,在 if 語句中它將返回 true,否則返回 false。如果你已經(jīng)檢測確認(rèn)該值存在,那么可以使用或者輸出它,在輸出的時候只需要在名稱后面加上感嘆號(!)即可,意思是告訴編譯器:我已經(jīng)檢測好這個值了,可以使用它了。
強(qiáng)制解包,是一種語法,在其它地方也可以使用,并非僅限于此。

選擇綁定:選擇綁定幫助確定一個可選值是不是包含了一個值,如果包含,把該值轉(zhuǎn)化成一個臨時常量或者變量(語法上使用 let)。選擇綁定可以用在 if 或 while 語句中,用來在可選類型外部檢查是否有值并提取可能的值。(條件判斷,并不一定需要是 Bool 類型!)

斷言

斷言會在運行時判斷一個邏輯條件是否為true。從字面意思來說,斷言“斷言”一個條件是否為真。你可以使用斷言來保證在運行其他代碼之前,某些重要的條件已經(jīng)被滿足。如果條件判斷為true,代碼運行會繼續(xù)進(jìn)行;如果條件判斷為false,代碼執(zhí)行結(jié)束,你的應(yīng)用被終止。

使用全局函數(shù) assert 來使用斷言調(diào)試,assert 函數(shù)接受一個布爾表達(dá)式和一個斷言失敗時顯示的消息。

帶標(biāo)簽的語句

label name: while condition { statements }

guard 提前退出

if語句一樣,guard的執(zhí)行取決于一個表達(dá)式的布爾值。我們可以使用guard語句來要求條件必須為真時,以執(zhí)行guard語句后的代碼。不同于if語句,一個guard語句總是有一個else分句,如果條件不為真則執(zhí)行else分局中的代碼。

guard condition else xxx 和其它語言里的 xxx unless condition 效果類似。

函數(shù)

沒有參數(shù)名字的函數(shù),復(fù)雜的帶局部和外部參數(shù)名的函數(shù)。參數(shù)可以提供默認(rèn)值,參數(shù)也可以既當(dāng)做傳入?yún)?shù),也當(dāng)做傳出參數(shù)。

每個函數(shù)都有一種類型,包括函數(shù)的參數(shù)值類型和返回值類型。

函數(shù)可以有多個輸入?yún)?shù),寫在圓括號中,用逗號分隔。

函數(shù)可以沒有參數(shù),但是定義中在函數(shù)名后還是需要一對圓括號。當(dāng)被調(diào)用時,也需要在函數(shù)名后寫一對圓括號。

函數(shù)可以沒有返回值。

函數(shù)的定義以 func 作為前綴,用返回箭頭 ->后跟返回類型的名稱的方式來表示返回類型。

嚴(yán)格上來說,沒有定義返回類型的函數(shù)會返回特殊的值,叫 Void。它其實是一個空的元組(tuple),沒有任何元素,可以寫成()

Swift 里輸入?yún)?shù)可以做得很復(fù)雜,支持泛型、函數(shù)等,記住一條不變法則:不論嵌套幾層,輸入?yún)?shù)始終要有 () 包裹著。

被調(diào)用時,一個函數(shù)的返回值可以被忽略。

你可以用元組(tuple)類型讓多個值作為一個復(fù)合值從函數(shù)中返回。

函數(shù)參數(shù)都有一個外部參數(shù)名(external parameter name)和一個本地參數(shù)名(local parameter name).外部參數(shù)名用來標(biāo)記傳遞給函數(shù)調(diào)用的參數(shù),本地參數(shù)名在實現(xiàn)函數(shù)的時候使用。(對于 Ruby 使用者而言,這是新的概念)

func someFunction(firstParameterName: Int, secondParameterName: Int) {
    // function body goes here
    // firstParameterName and secondParameterName refer to
    // the argument values for the first and second parameters
}
someFunction(1, secondParameterName: 2)

一般情況下,第一個參數(shù)省略其外部參數(shù)名,第二個以后的參數(shù)使用其本地參數(shù)名作為自己的外部參數(shù)名.所有參數(shù)需要有不同的本地參數(shù)名,但可以共享相同的外部參數(shù)名.

類似 Ruby 里傳遞哈希、或多參數(shù),視覺上更好對應(yīng),自動匹配。只不過,對于 Swift 來說,感覺有點怪。

如果你提供了外部參數(shù)名,那么函數(shù)在被調(diào)用時,必須使用外部參數(shù)名。(記得,以哈希的形式調(diào)用哈~)

func sayHello(to person: String, and anotherPerson: String) -> String {
    return "Hello \(person) and \(anotherPerson)!"
}

sayHello(to: "Bill", and: "Ted")
// prints "Hello Bill and Ted!"

如果你不想為第二個及后續(xù)的參數(shù)設(shè)置參數(shù)名,用一個下劃線(_)代替一個明確地參數(shù)名。因為第一個參數(shù)默認(rèn)忽略其外部參數(shù)名稱,明確寫下劃線是多余的。(在這里,既然都忽略了,那干脆直接的、不使用此特性,不行嗎)

你可以在函數(shù)體中為每個參數(shù)定義默認(rèn)值(Deafult Values)。當(dāng)默認(rèn)值被定義后,調(diào)用這個函數(shù)時可以忽略這個參數(shù)。
將帶有默認(rèn)值的參數(shù)放在函數(shù)參數(shù)列表的最后。這樣可以保證在函數(shù)調(diào)用時,非默認(rèn)參數(shù)的順序是一致的,同時使得相同的函數(shù)在不同情況下調(diào)用時顯得更為清晰。

一個可變參數(shù)(variadic parameter)可以接受零個或多個值。函數(shù)調(diào)用時,你可以用可變參數(shù)來傳入不確定數(shù)量的輸入?yún)?shù)。通過在變量類型名后面加入(...)的方式來定義可變參數(shù)。
傳入可變參數(shù)的值在函數(shù)體內(nèi)當(dāng)做這個類型的一個數(shù)組。

函數(shù)參數(shù)默認(rèn)是常量。試圖在函數(shù)體中更改參數(shù)值將會導(dǎo)致編譯錯誤。這意味著你不能錯誤地更改參數(shù)值。

但是,有時候,如果函數(shù)中有傳入?yún)?shù)的變量值副本將是很有用的。你可以通過指定一個或多個參數(shù)為變量參數(shù),從而避免自己在函數(shù)中定義新的變量。變量參數(shù)不是常量,你可以在函數(shù)中把它當(dāng)做新的可修改副本來使用。

通過在參數(shù)名前加關(guān)鍵字 var 來定義變量參數(shù)。

對變量參數(shù)所進(jìn)行的修改在函數(shù)調(diào)用結(jié)束后便消失了,并且對于函數(shù)體外是不可見的。變量參數(shù)僅僅存在于函數(shù)調(diào)用的生命周期中。

變量參數(shù),正如上面所述,僅僅能在函數(shù)體內(nèi)被更改。如果你想要一個函數(shù)可以修改參數(shù)的值,并且想要在這些修改在函數(shù)調(diào)用結(jié)束后仍然存在,那么就應(yīng)該把這個參數(shù)定義為輸入輸出參數(shù)(In-Out Parameters)。

定義一個輸入輸出參數(shù)時,在參數(shù)定義前加 inout 關(guān)鍵字。一個輸入輸出參數(shù)有傳入函數(shù)的值,這個值被函數(shù)修改,然后被傳出函數(shù),替換原來的值。

你只能將變量作為輸入輸出參數(shù)。你不能傳入常量或者字面量(literal value),因為這些量是不能被修改的。當(dāng)傳入的參數(shù)作為輸入輸出參數(shù)時,需要在參數(shù)前加&符,表示這個值可以被函數(shù)修改。(調(diào)用的時候,變量前加 & 表示傳遞的是引用)

輸入輸出參數(shù)是函數(shù)對函數(shù)體外產(chǎn)生影響的另一種方式。

每個函數(shù)都有種特定的函數(shù)類型,由函數(shù)的參數(shù)類型和返回類型組成。

使用函數(shù)類型

在 Swift 中,使用函數(shù)類型就像使用其他類型一樣。例如,你可以定義一個類型為函數(shù)的常量或變量,并將函數(shù)賦值給它:

var mathFunction: (Int, Int) -> Int = addTwoInts

變量是 mathFunction 類型是函數(shù) addTwoInts 而此函數(shù)的輸入、輸出類型分別是 (Int, Int)Int

函數(shù)類型作為參數(shù)類型

你可以用(Int, Int) -> Int這樣的函數(shù)類型作為另一個函數(shù)的參數(shù)類型。這樣你可以將函數(shù)的一部分實現(xiàn)交由給函數(shù)的調(diào)用者。

下面是另一個例子,正如上面的函數(shù)一樣,同樣是輸出某種數(shù)學(xué)運算結(jié)果:

func printMathResult(mathFunction: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Result: \(mathFunction(a, b))")
}

printMathResult(addTwoInts, 3, 5)
// prints "Result: 8"

被嵌套函數(shù)在調(diào)用時,函數(shù)參數(shù)為 in 前面的代碼,函數(shù)體為 in 后面的代碼。
被嵌套函數(shù)的類型是可預(yù)先知道的,并且定義調(diào)用同時進(jìn)行。

函數(shù)類型作為返回類型

你可以用函數(shù)類型作為另一個函數(shù)的返回類型。你需要做的是在返回箭頭(->)后寫一個完整的函數(shù)類型。

func chooseStepFunction(backwards: Bool) -> (Int) -> Int {
    return backwards ? stepBackward : stepForward
}

以第一個 -> 為分隔,輸入?yún)?shù)類型為 (backwards: Bool),輸出也就是返回類型為 (Int) -> Int

嵌套函數(shù)

全局函數(shù),定義在全局域中。嵌套函數(shù),定義在別的函數(shù)體中。

閉包

閉包采取如下三種形式之一:

  • 全局函數(shù)是一個有名字但不會捕獲任何值的閉包
  • 嵌套函數(shù)是一個有名字并可以捕獲其封閉函數(shù)域內(nèi)值的閉包
  • 閉包表達(dá)式是一個利用輕量級語法所寫的可以捕獲其上下文中變量或常量值的匿名閉包

sort(_:)方法需要傳入兩個參數(shù):

  • 已知類型的數(shù)組
  • 閉包函數(shù),該閉包函數(shù)需要傳入與數(shù)組元素類型相同的兩個值,并返回一個布爾類型值來表明當(dāng)排序結(jié)束后傳入的第一個參數(shù)排在第二個參數(shù)前面還是后面。如果第一個參數(shù)值出現(xiàn)在第二個參數(shù)值前面,排序閉包函數(shù)需要返回true,反之返回false。

和 Ruby 里 map 等方法一樣的,容易理解。

閉包表達(dá)式語法有如下一般形式:

{ (parameters) -> returnType in
    statements
}

parameters 表示輸入?yún)?shù),returnType 表示輸出類型,in 是關(guān)鍵字表示開始執(zhí)行內(nèi)容,statements 表示執(zhí)行內(nèi)容。

根據(jù)上下文推斷類型

實際上任何情況下,通過內(nèi)聯(lián)閉包表達(dá)式構(gòu)造的閉包作為參數(shù)傳遞給函數(shù)時,都可以推斷出閉包的參數(shù)和返回值類型,這意味著您幾乎不需要利用完整格式構(gòu)造任何內(nèi)聯(lián)閉包。

也就是說,輸入?yún)?shù)的類型和輸出類型是可省的。

reversed = names.sort( { s1, s2 in return s1 > s2 } )

單表達(dá)式閉包隱式返回

單行表達(dá)式閉包可以通過隱藏return關(guān)鍵字來隱式返回單行表達(dá)式。

參數(shù)名稱縮寫

Swift 自動為內(nèi)聯(lián)函數(shù)提供了參數(shù)名稱縮寫功能,您可以直接通過$0,$1,$2來順序調(diào)用閉包的參數(shù)。

in關(guān)鍵字也同樣可以被省略,因為此時閉包表達(dá)式完全由閉包函數(shù)體構(gòu)成。

運算符函數(shù)

reversed = names.sort(>)

省略到極致,真的能看懂嗎?

尾隨閉包

如果您需要將一個很長的閉包表達(dá)式作為最后一個參數(shù)傳遞給函數(shù),可以使用尾隨閉包來增強(qiáng)函數(shù)的可讀性。
尾隨閉包是一個書寫在函數(shù)括號之后的閉包表達(dá)式,函數(shù)支持將其作為最后一個參數(shù)調(diào)用。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函數(shù)體部分
}

// 以下是不使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure({
    // 閉包主體部分
})

// 以下是使用尾隨閉包進(jìn)行函數(shù)調(diào)用
someFunctionThatTakesAClosure() {
  // 閉包主體部分
}

捕獲值

Swift最簡單的閉包形式是嵌套函數(shù),也就是定義在其他函數(shù)的函數(shù)體內(nèi)的函數(shù)。
嵌套函數(shù)可以捕獲其外部函數(shù)所有的參數(shù)以及定義的常量和變量。

閉包是引用類型

無論您將函數(shù)/閉包賦值給一個常量還是變量,您實際上都是將常量/變量的值設(shè)置為對應(yīng)函數(shù)/閉包的引用。

枚舉

在 Swift 中,枚舉類型是一等公民(first-class)。它們采用了很多傳統(tǒng)上只被類(class)所支持的特征,例如計算型屬性(computed properties),用于提供關(guān)于枚舉當(dāng)前值的附加信息,實例方法(instance methods),用于提供和枚舉所代表的值相關(guān)聯(lián)的功能。枚舉也可以定義構(gòu)造函數(shù)(initializers)來提供一個初始值;可以在原始的實現(xiàn)基礎(chǔ)上擴(kuò)展它們的功能;可以遵守協(xié)議(protocols)來提供標(biāo)準(zhǔn)的功能。

使用enum關(guān)鍵詞來創(chuàng)建枚舉并且把它們的整個定義放在一對大括號內(nèi):

enum SomeEnumeration {
  // enumeration definition goes here
}

里面的內(nèi)容被稱為 成員值。

多個成員值可以出現(xiàn)在同一行上,用逗號隔開。

一旦一個變量,被賦值為一個枚舉的成員值,你可以使用一個縮寫語法(.)將其設(shè)置為另一個成員值

你可以使用switch語句匹配單個枚舉值。

作為相關(guān)值的另一種選擇,枚舉成員可以被默認(rèn)值賦值(語法上,和普通的賦值一樣),其中這些原始值具有相同的類型(聲明的時候要標(biāo)注)。
你也可以在枚舉類型開頭加上indirect關(guān)鍵字來表示它的所有成員都是可遞歸的。

定義:

enum Result<T, U> {
  case Success(T)
  case Failure(U)
}

枚舉,和類一樣,可以當(dāng)做普通變量的“類型”。

調(diào)用:

let aSuccess : Result<Int, String> = .Success(123)let aFailure : Result<Int, String> = .Failure("temperature too high")

注意:定義時對泛型的支持,調(diào)用時對泛型的指定。

類和結(jié)構(gòu)體

類和結(jié)構(gòu)體對比

Swift 中類和結(jié)構(gòu)體有很多共同點。共同處在于:

  • 定義屬性用于存儲值
  • 定義方法用于提供功能
  • 定義附屬腳本用于訪問值
  • 定義構(gòu)造器用于生成初始化值
  • 通過擴(kuò)展以增加默認(rèn)實現(xiàn)的功能
  • 實現(xiàn)協(xié)議以提供某種標(biāo)準(zhǔn)功能

與結(jié)構(gòu)體相比,類還有如下的附加功能:

  • 繼承允許一個類繼承另一個類的特征
  • 類型轉(zhuǎn)換允許在運行時檢查和解釋一個類實例的類型
  • 解構(gòu)器允許一個類實例釋放任何其所被分配的資源
  • 引用計數(shù)允許對一個類的多次引用

定義

類和結(jié)構(gòu)體有著類似的定義方式。我們通過關(guān)鍵字classstruct來分別表示類和結(jié)構(gòu)體,并在一對大括號中定義它們的具體內(nèi)容。

生成結(jié)構(gòu)體和類實例的語法一樣。

通過使用 .,你可以訪問實例中所含有的屬性。
你也可以使用點語法為屬性變量賦值。

所有結(jié)構(gòu)體都有一個自動生成的成員逐一構(gòu)造器,用于初始化新結(jié)構(gòu)體實例中成員的屬性。新實例中各個屬性的初始值可以通過屬性的名稱傳遞到成員逐一構(gòu)造器之中:

let vga = Resolution(width:640, height: 480)

以哈希的形式傳參,創(chuàng)建對應(yīng)的實例,很正常啊。

結(jié)構(gòu)體和枚舉是值類型

在 Swift 中,所有的結(jié)構(gòu)體和枚舉類型都是值類型。這意味著它們的實例,以及實例中所包含的任何值類型屬性,在代碼中傳遞的時候都會被復(fù)制。

類是引用類型

與值類型不同,引用類型在被賦予到一個變量、常量或者被傳遞到一個函數(shù)時,操作的是引用,其并不是拷貝。因此,引用的是已存在的實例本身而不是其拷貝。

如果能夠判定兩個常量或者變量是否引用同一個類實例將會很有幫助。為了達(dá)到這個目的,Swift 內(nèi)建了兩個恒等運算符:

恒等運算符

  • 等價于 ( === )
  • 不等價于 ( !== )

指針

概念被弱化了,甚至可以說沒有了。

絕大部分的自定義數(shù)據(jù)構(gòu)造都應(yīng)該是類,而非結(jié)構(gòu)體。

Swift 中字符串(String),數(shù)組(Array)字典(Dictionary)類型均以結(jié)構(gòu)體的形式實現(xiàn)。

屬性

存儲屬性可以是變量存儲屬性(用關(guān)鍵字var定義),也可以是常量存儲屬性(用關(guān)鍵字let定義)。

如果創(chuàng)建了一個結(jié)構(gòu)體的實例并將其賦值給一個常量,則無法修改該實例的任何屬性,即使定義了變量存儲屬性。

延遲存儲屬性

第一次被調(diào)用的時候才會計算其初始值的屬性。在屬性聲明前使用 lazy 來標(biāo)示一個延遲存儲屬性。

如果一個被標(biāo)記為 lazy 的屬性在沒有初始化時就同時被多個線程訪問,則無法保證該屬性只會被初始化一次。

計算屬性

除存儲屬性外,類、結(jié)構(gòu)體和枚舉可以定義計算屬性。計算屬性不直接存儲值,而是提供一個 getter 和一個可選的 setter,來間接獲取和設(shè)置其他屬性或變量的值。

如果計算屬性的 setter 沒有定義表示新值的參數(shù)名,則可以使用默認(rèn)名稱newValue。

只讀計算屬性的聲明可以去掉get關(guān)鍵字和花括號。

屬性觀察器

屬性觀察器監(jiān)控和響應(yīng)屬性值的變化,每次屬性被設(shè)置值的時候都會調(diào)用屬性觀察器,甚至新的值和現(xiàn)在的值相同的時候也不例外。

可以為屬性添加如下的一個或全部觀察器:

  • willSet在新的值被設(shè)置之前調(diào)用
  • didSet在新的值被設(shè)置之后立即調(diào)用

計算屬性和屬性觀察器所描述的模式也可以用于全局變量局部變量。全局變量是在函數(shù)、方法、閉包或任何類型之外定義的變量。局部變量是在函數(shù)、方法或閉包內(nèi)部定義的變量。

類型屬性

為類型本身定義屬性,不管類型有多少個實例,這些屬性都只有唯一一份。這種屬性就是類型屬性。

使用關(guān)鍵字static來定義類型屬性。

跟實例的屬性一樣,類型屬性的訪問也是通過點運算符來進(jìn)行。但是,類型屬性是通過類型本身來獲取和設(shè)置,而不是通過實例。

類似“類變量”。

方法

實例方法是屬于某個特定類、結(jié)構(gòu)體或者枚舉類型實例的方法。

實例方法的語法與函數(shù)完全一致。

和調(diào)用屬性一樣,用點語法(dot syntax)調(diào)用實例方法。

方法的局部參數(shù)名稱和外部參數(shù)名稱 - 和函數(shù)一樣。

修改方法的外部參數(shù)名稱。

1)你可以自己添加一個顯式的外部名稱或者用一個井號(#)作為第一個參數(shù)的前綴來把這個局部名稱當(dāng)作外部名稱使用。

2)相反,如果你不想為方法的第二個及后續(xù)的參數(shù)提供一個外部名稱,可以通過使用下劃線(_)作為該參數(shù)的顯式外部名稱,這樣做將覆蓋默認(rèn)行為。

類型的每一個實例都有一個隱含屬性叫做self,self完全等同于該實例本身。你可以在一個實例的實例方法中使用這個隱含的self屬性來引用當(dāng)前實例。

使用self屬性來區(qū)分參數(shù)名稱和屬性名稱。
實例方法的某個參數(shù)名稱與實例的某個屬性名稱相同的時候。在這種情況下,參數(shù)名稱享有優(yōu)先權(quán),并且在引用屬性時必須使用一種更嚴(yán)格的方式。

在實例方法中修改值類型

結(jié)構(gòu)體和枚舉是值類型。一般情況下,值類型的屬性不能在它的實例方法中被修改。

但是,如果你確實需要在某個具體的方法中修改結(jié)構(gòu)體或者枚舉的屬性,你可以選擇變異(mutating)這個方法。

要使用變異方法, 將關(guān)鍵字mutating 放到方法的func關(guān)鍵字之前就可以了。

在變異方法中給self賦值

變異方法能夠賦給隱含屬性self一個全新的實例。

枚舉的變異方法可以把self設(shè)置為相同的枚舉類型中不同的成員。

** 類型方法**

聲明結(jié)構(gòu)體和枚舉的類型方法,在方法的func關(guān)鍵字之前加上關(guān)鍵字static。

俗稱的“類方法”。

下標(biāo)腳本

下標(biāo)腳本允許你通過在實例后面的方括號中傳入一個或者多個的索引值來對實例進(jìn)行訪問和賦值。

與定義實例方法類似,定義下標(biāo)腳本使用subscript關(guān)鍵字,顯式聲明入?yún)ⅲㄒ粋€或多個)和返回類型。與實例方法不同的是下標(biāo)腳本可以設(shè)定為讀寫或只讀。這種方式又有點像計算型屬性的getter和setter:

subscript(index: Int) -> Int {
    get {
      // 返回與入?yún)⑵ヅ涞腎nt類型的值
    }

    set(newValue) {
      // 執(zhí)行賦值操作
    }
}

newValue的類型必須和下標(biāo)腳本定義的返回類型相同。與計算型屬性相同的是set的入?yún)⒙暶?code>newValue就算不寫,在set代碼塊中依然可以使用默認(rèn)的newValue這個變量來訪問新賦的值。

下標(biāo)腳本允許任意數(shù)量的入?yún)⑺饕⑶颐總€入?yún)㈩愋鸵矝]有限制。下標(biāo)腳本的返回值也可以是任何類型。下標(biāo)腳本可以使用變量參數(shù)和可變參數(shù),但使用寫入讀出(in-out)參數(shù)或給參數(shù)設(shè)置默認(rèn)值都是不允許的。

一個類或結(jié)構(gòu)體可以根據(jù)自身需要提供多個下標(biāo)腳本實現(xiàn),在定義下標(biāo)腳本時通過入?yún)€類型進(jìn)行區(qū)分,使用下標(biāo)腳本時會自動匹配合適的下標(biāo)腳本實現(xiàn)運行,這就是下標(biāo)腳本的重載。

繼承

Swift 中的類并不是從一個通用的基類繼承而來。如果你不為你定義的類指定一個超類的話,這個類就自動成為基類。

如果要重寫某個特性,你需要在重寫定義的前面加上override關(guān)鍵字。

在合適的地方,你可以通過使用super前綴來訪問超類版本的方法,屬性或下標(biāo)腳本。

你可以通過把方法,屬性或下標(biāo)腳本標(biāo)記為final來防止它們被重寫,只需要在聲明關(guān)鍵字前加上final特性即可。

構(gòu)造過程

構(gòu)造器在創(chuàng)建某特定類型的新實例時調(diào)用。它的最簡形式類似于一個不帶任何參數(shù)的實例方法,以關(guān)鍵字init命名。

你可以在定義構(gòu)造器時提供構(gòu)造參數(shù),為其提供自定義構(gòu)造所需值的類型和名字。構(gòu)造器參數(shù)的功能和語法跟函數(shù)和方法參數(shù)相同。

Swift 會默認(rèn)為每個構(gòu)造器的參數(shù)自動生成一個跟內(nèi)部名字相同的外部名,就相當(dāng)于在每個構(gòu)造參數(shù)之前加了一個哈希符號。(這是特性之一,也是和普通方法的區(qū)別之一)

如果你不希望為構(gòu)造器的某個參數(shù)提供外部名字,你可以使用下劃線(_)來顯示描述它的外部名,以此重寫上面所說的默認(rèn)行為。

指定構(gòu)造器和便利構(gòu)造器

類的指定構(gòu)造器的寫法跟值類型簡單構(gòu)造器一樣:

init(parameters) {
    statements
}

便利構(gòu)造器也采用相同樣式的寫法,但需要在init關(guān)鍵字之前放置convenience關(guān)鍵字,并使用空格將它們倆分開。

convenience init(parameters) {
    statements
}

如果一個類,結(jié)構(gòu)體或枚舉類型的對象,在構(gòu)造自身的過程中有可能失敗,則為其定義一個可失敗構(gòu)造器,是非常有必要的。
你可以在一個類,結(jié)構(gòu)體或是枚舉類型的定義中,添加一個或多個可失敗構(gòu)造器。其語法為在init關(guān)鍵字后面加添問號(init?)。

帶原始值的枚舉類型會自帶一個可失敗構(gòu)造器init?(rawValue:),該可失敗構(gòu)造器有一個名為rawValue的默認(rèn)參數(shù),其類型和枚舉類型的原始值類型一致,如果該參數(shù)的值能夠和枚舉類型成員所帶的原始值匹配,則該構(gòu)造器構(gòu)造一個帶此原始值的枚舉成員,否則構(gòu)造失敗。

通常來說我們通過在init關(guān)鍵字后添加問號的方式來定義一個可失敗構(gòu)造器,但你也可以使用通過在init后面添加驚嘆號的方式來定義一個可失敗構(gòu)造器(init!),該可失敗構(gòu)造器將會構(gòu)建一個特定類型的隱式解析可選類型的對象。

你可以在 init?構(gòu)造器中代理調(diào)用 init!構(gòu)造器,反之亦然。
你也可以用 init?重寫 init!,反之亦然。
你還可以用 init代理調(diào)用init!,但這會觸發(fā)一個斷言:是否 init! 構(gòu)造器會觸發(fā)構(gòu)造失?。?/p>

在類的構(gòu)造器前添加 required 修飾符表明所有該類的子類都必須實現(xiàn)該構(gòu)造器:

class SomeClass {
    required init() {
        // 在這里添加該必要構(gòu)造器的實現(xiàn)代碼
    }
}

當(dāng)子類重寫基類的必要構(gòu)造器時,必須在子類的構(gòu)造器前同樣添加required修飾符以確保當(dāng)其它類繼承該子類時,該構(gòu)造器同為必要構(gòu)造器。在重寫基類的必要構(gòu)造器時,不需要添加override修飾符:

class SomeSubclass: SomeClass {
    required init() {
        // 在這里添加子類必要構(gòu)造器的實現(xiàn)代碼
    }
}

如果某個存儲型屬性的默認(rèn)值需要特別的定制或準(zhǔn)備,你就可以使用閉包或全局函數(shù)來為其屬性提供定制的默認(rèn)值。每當(dāng)某個屬性所屬的新類型實例創(chuàng)建時,對應(yīng)的閉包或函數(shù)會被調(diào)用,而它們的返回值會當(dāng)做默認(rèn)值賦值給這個屬性。
注意閉包結(jié)尾的大括號后面接了一對空的小括號。

析構(gòu)過程

析構(gòu)器只適用于類類型,當(dāng)一個類的實例被釋放之前,析構(gòu)器會被立即調(diào)用。析構(gòu)器用關(guān)鍵字deinit來標(biāo)示,類似于構(gòu)造器要用init來標(biāo)示。

在類的定義中,每個類最多只能有一個析構(gòu)器,而且析構(gòu)器不帶任何參數(shù)。

解決實例之間的循環(huán)強(qiáng)引用

Swift 提供了兩種辦法用來解決你在使用類的屬性時所遇到的循環(huán)強(qiáng)引用問題:弱引用(weak reference)和無主引用(unowned reference)。

弱引用不會對其引用的實例保持強(qiáng)引用,因而不會阻止 ARC 銷毀被引用的實例。這個特性阻止了引用變?yōu)檠h(huán)強(qiáng)引用。聲明屬性或者變量時,在前面加上weak關(guān)鍵字表明這是一個弱引用。

和弱引用類似,無主引用不會牢牢保持住引用的實例。和弱引用不同的是,無主引用是永遠(yuǎn)有值的。因此,無主引用總是被定義為非可選類型(non-optional type)。你可以在聲明屬性或者變量時,在前面加上關(guān)鍵字unowned表示這是一個無主引用。

捕獲列表中的每一項都由一對元素組成,一個元素是weakunowned關(guān)鍵字,另一個元素是類實例的引用(如self)或初始化過的變量(如delegate = self.delegate!)。這些項在方括號中用逗號分開。

如果閉包沒有指明參數(shù)列表或者返回類型,即它們會通過上下文推斷,那么可以把捕獲列表和關(guān)鍵字in放在閉包最開始的地方。

可空鏈?zhǔn)秸{(diào)用

在鏈?zhǔn)秸{(diào)用過程中 ?! 的使用。

錯誤處理

在Swift中,錯誤用符合ErrorType協(xié)議的值表示。

Swift枚舉特別適合把一系列相關(guān)的錯誤組合在一起,同時可以把一些相關(guān)的值和錯誤關(guān)聯(lián)在一起。因此編譯器會為實現(xiàn)ErrorType協(xié)議的Swift枚舉類型自動實現(xiàn)相應(yīng)合成。

通過在函數(shù)或方法聲明的參數(shù)后面加上throws關(guān)鍵字,表明這個函數(shù)或方法可以拋出錯誤。如果指定一個返回值,可以把throws關(guān)鍵字放在返回箭頭(->)的前面。

在拋出函數(shù)體的任意一個地方,可以通過throw語句拋出錯誤。

當(dāng)調(diào)用一個拋出函數(shù)的時候,在調(diào)用前面加上try。這個關(guān)鍵字表明函數(shù)可以拋出錯誤,而且在try后面代碼將不會執(zhí)行。

使用do-catch語句來就捕獲和處理錯誤。

do {
    try function that throws
    statements
} catch pattern {
    statements
}

使用了 do 的其它語法:

do {
  let a = Animals.Troll
  ...
}

在運行時,有幾種情況拋出函數(shù)事實上是不會拋出錯誤的。在這幾種情況下,你可以用forced-try表達(dá)式來調(diào)用拋出函數(shù)或方法,即使用try!來代替try。

使用defer語句來在執(zhí)行一系列的語句。這樣不管有沒有錯誤發(fā)生,都可以執(zhí)行一些必要的收尾操作。

類型轉(zhuǎn)換

類型轉(zhuǎn)換在 Swift 中使用 isas 操作符實現(xiàn)。這兩個操作符提供了一種簡單達(dá)意的方式去檢查值的類型或者轉(zhuǎn)換它的類型。

用類型檢查操作符(is)來檢查一個實例是否屬于特定子類型。若實例屬于那個子類型,類型檢查操作符返回 true,否則返回 false。

某類型的一個常量或變量可能在幕后實際上屬于一個子類。當(dāng)確定是這種情況時,你可以嘗試向下轉(zhuǎn)到它的子類型,用類型轉(zhuǎn)換操作符(as?as!)

因為向下轉(zhuǎn)型可能會失敗,類型轉(zhuǎn)型操作符帶有兩種不同形式。條件形式(conditional form) as? 返回一個你試圖向下轉(zhuǎn)成的類型的可選值(optional value)。強(qiáng)制形式 as! 把試圖向下轉(zhuǎn)型和強(qiáng)制解包(force-unwraps)結(jié)果作為一個混合動作。

轉(zhuǎn)換沒有真的改變實例或它的值。潛在的根本的實例保持不變;只是簡單地把它作為它被轉(zhuǎn)換成的類來使用。

Swift為不確定類型提供了兩種特殊類型別名:

  • AnyObject可以代表任何class類型的實例。
  • Any可以表示任何類型,包括方法類型(function types)。

嵌套類型

在外部對嵌套類型的引用,以被嵌套類型的名字為前綴,加上所要引用的屬性名。

擴(kuò)展

擴(kuò)展就是向一個已有的類、結(jié)構(gòu)體、枚舉類型或者協(xié)議類型添加新功能(functionality)。

Swift 中的擴(kuò)展可以:

  • 添加計算型屬性和計算型靜態(tài)屬性
  • 定義實例方法和類型方法
  • 提供新的構(gòu)造器
  • 定義下標(biāo)
  • 定義和使用新的嵌套類型
  • 使一個已有類型符合某個協(xié)議

聲明一個擴(kuò)展使用關(guān)鍵字extension

1)擴(kuò)展可以向已有類型添加計算型實例屬性和計算型類型屬性。
2)擴(kuò)展可以向已有類型添加新的構(gòu)造器。
3)擴(kuò)展可以向已有類型添加新的實例方法和類型方法。
4)通過擴(kuò)展添加的實例方法也可以修改該實例本身。
5)擴(kuò)展可以向一個已有類型添加新下標(biāo)。
6)擴(kuò)展可以向已有的類、結(jié)構(gòu)體和枚舉添加新的嵌套類型。

協(xié)議

協(xié)議定義了一個藍(lán)圖,規(guī)定了用來實現(xiàn)某一特定工作或者功能所必需的方法和屬性。類,結(jié)構(gòu)體或枚舉類型都可以遵循協(xié)議,并提供具體實現(xiàn)來完成協(xié)議定義的方法和功能。任意能夠滿足協(xié)議要求的類型被稱為遵循(conform)這個協(xié)議。

協(xié)議的定義方式與類,結(jié)構(gòu)體,枚舉的定義非常相似。

要使類遵循某個協(xié)議,需要在類型名稱后加上協(xié)議名稱,中間以冒號:分隔,作為類型定義的一部分。遵循多個協(xié)議時,各協(xié)議之間用逗號,分隔。

如果類在遵循協(xié)議的同時擁有父類,應(yīng)該將父類名放在協(xié)議名之前,以逗號分隔。

1、對屬性的規(guī)定

協(xié)議可以規(guī)定其遵循者提供特定名稱和類型的實例屬性(instance property)類屬性(type property),而不指定是存儲型屬性(stored property)還是計算型屬性(calculate property)。此外還必須指明是只讀的還是可讀可寫的。

** 2、對方法的規(guī)定**

協(xié)議可以要求其遵循者實現(xiàn)某些指定的實例方法或類方法。這些方法作為協(xié)議的一部分,像普通的方法一樣放在協(xié)議的定義中,但是不需要大括號和方法體??梢栽趨f(xié)議中定義具有可變參數(shù)的方法,和普通方法的定義方式相同。但是在協(xié)議的方法定義中,不支持參數(shù)默認(rèn)值。

3、對Mutating方法的規(guī)定

有時需要在方法中改變它的實例。例如,值類型(結(jié)構(gòu)體,枚舉)的實例方法中,將mutating關(guān)鍵字作為函數(shù)的前綴,寫在func之前,表示可以在該方法中修改它所屬的實例及其實例屬性的值。

和 Ruby 里某些方法帶 ! 是一個道理,因為調(diào)用這些方法后,會改變對象本身?;蛘哒f,具有破壞性。

4、對構(gòu)造器的規(guī)定

協(xié)議可以要求它的遵循者實現(xiàn)指定的構(gòu)造器。你可以像書寫普通的構(gòu)造器那樣,在協(xié)議的定義里寫下構(gòu)造器的聲明,但不需要寫花括號和構(gòu)造器的實體。

協(xié)議類型

盡管協(xié)議本身并不實現(xiàn)任何功能,但是協(xié)議可以被當(dāng)做類型來使用。

協(xié)議可以像其他普通類型一樣使用,使用場景:

  • 作為函數(shù)、方法或構(gòu)造器中的參數(shù)類型或返回值類型
  • 作為常量、變量或?qū)傩缘念愋?/li>
  • 作為數(shù)組、字典或其他容器中的元素類型

協(xié)議能夠繼承一個或多個其他協(xié)議,可以在繼承的協(xié)議基礎(chǔ)上增加新的內(nèi)容要求。協(xié)議的繼承語法與類的繼承相似,多個被繼承的協(xié)議間用逗號分隔。

類專屬協(xié)議

你可以在協(xié)議的繼承列表中,通過添加 class 關(guān)鍵字, 限制協(xié)議只能適配到類(class)類型。(結(jié)構(gòu)體或枚舉不能遵循該協(xié)議)。該class關(guān)鍵字必須是第一個出現(xiàn)在協(xié)議的繼承列表中,其后,才是其他繼承協(xié)議。

協(xié)議合成

有時候需要同時遵循多個協(xié)議。你可以將多個協(xié)議采用protocol<SomeProtocol, AnotherProtocol>這樣的格式進(jìn)行組合,稱為協(xié)議合成(protocol composition)。你可以在<>中羅列任意多個你想要遵循的協(xié)議,以逗號分隔。

protocol<SomeProtocol, AnotherProtocol> 前面的 protocol 是關(guān)鍵字,<> 里面是各個協(xié)議的名字。
協(xié)議合成并不會生成一個新協(xié)議類型,而是將多個協(xié)議合成為一個臨時的協(xié)議,超出范圍后立即失效。

檢驗協(xié)議的一致性

  • is操作符用來檢查實例是否遵循了某個協(xié)議
  • as?返回一個可選值,當(dāng)實例遵循協(xié)議時,返回該協(xié)議類型;否則返回nil
  • as用以強(qiáng)制向下轉(zhuǎn)型,如果強(qiáng)轉(zhuǎn)失敗,會引起運行時錯誤。

協(xié)議可以含有可選成員,其遵循者可以選擇是否實現(xiàn)這些成員。在協(xié)議中使用optional關(guān)鍵字作為前綴來定義可選成員。

為協(xié)議擴(kuò)展添加限制條件

在擴(kuò)展協(xié)議的時候,可以指定一些限制,只有滿足這些限制的協(xié)議遵循者,才能獲得協(xié)議擴(kuò)展提供的屬性和方法。這些限制寫在協(xié)議名之后,使用where關(guān)鍵字來描述限制情況。

泛型

函數(shù)功能都是相同的,唯一不同之處就在于傳入的變量類型不同。

泛型函數(shù)名后面跟著的占位類型名字(T)是用尖括號括起來的(<T>)。
你可支持多個類型參數(shù),命名在尖括號中,用逗號分開。

當(dāng)你擴(kuò)展一個泛型類型的時候,你并不需要在擴(kuò)展的定義中提供類型參數(shù)列表。更加方便的是,原始類型定義中聲明的類型參數(shù)列表在擴(kuò)展里是可以使用的,并且這些來自原始類型中的參數(shù)名稱會被用作原始定義中類型參數(shù)的引用。

泛型函數(shù)使用了占位類型(通常此情況下用字母T來表示)來代替實際類型(如Int、StringDouble)。

另外一個不同之處在于這個泛型函數(shù)名后面跟著的占位類型(T)是用尖括號括起來的(<T>)。這個尖括號告訴 Swift 那個T是函數(shù)所定義的一個類型。但因為T是一個占位類型,Swift 不會去查找命名為T的實際類型。

類型約束

你可以寫一個在一個類型參數(shù)名后面的類型約束,通過冒號分割,來作為類型參數(shù)鏈的一部分。

關(guān)聯(lián)類型

當(dāng)定義一個協(xié)議時,有的時候聲明一個或多個關(guān)聯(lián)類型作為協(xié)議定義的一部分是非常有用的。一個關(guān)聯(lián)類型作為協(xié)議的一部分,給定了類型的一個占位名(或別名)。作用于關(guān)聯(lián)類型上實際類型在協(xié)議被實現(xiàn)前是不需要指定的。關(guān)聯(lián)類型被指定為typealias關(guān)鍵字。

typealias ItemType。這個協(xié)議不會定義ItemType是什么的別名,這個信息將由任何遵循協(xié)議的類型來提供。

這里的 typealias 和類型別名,意義是不一樣的。遵行此協(xié)議的“類”,總得有對應(yīng)的“類型”吧。但是這個“類型”具體是什么,又不能確定,那么先用 ItemType 代替。(因為協(xié)議里面要用了,不能不提供;僅/只能提供一次)

Where 語句

對關(guān)聯(lián)類型定義約束是非常有用的。你可以在參數(shù)列表中通過where語句定義參數(shù)的約束。一個where語句能夠使一個關(guān)聯(lián)類型遵循一個特定的協(xié)議,以及(或)那個特定的類型參數(shù)和關(guān)聯(lián)類型可以是相同的。你可以寫一個where語句,緊跟在在類型參數(shù)列表后面,where語句后跟一個或者多個針對關(guān)聯(lián)類型的約束,以及(或)一個或多個類型和關(guān)聯(lián)類型間的等價(equality)關(guān)系。

訪問控制

Swift 中的訪問控制模型基于模塊和源文件這兩個概念。

模塊指的是以獨立單元構(gòu)建和發(fā)布的FrameworkApplication。在Swift 中的一個模塊可以使用import關(guān)鍵字引入另外一個模塊。

源文件指的是 Swift 中的Swift File,就是編寫 Swift 源代碼的文件,它通常屬于一個模塊。盡管一般我們將不同的 分別定義在不同的源文件中,但是同一個源文件可以包含多個函數(shù) 的定義。

Swift 為代碼中的實體提供了三種不同的訪問級別。這些訪問級別不僅與源文件中定義的實體相關(guān),同時也與源文件所屬的模塊相關(guān)。

  • public:可以訪問自己模塊中源文件里的任何實體,別人也可以通過引入該模塊來訪問源文件里的所有實體。通常情況下,Framework 中的某個接口是可以被任何人使用時,你可以將其設(shè)置為public級別。
  • internal:可以訪問自己模塊中源文件里的任何實體,但是別人不能訪問該模塊中源文件里的實體。通常情況下,某個接口或Framework作為內(nèi)部結(jié)構(gòu)使用時,你可以將其設(shè)置為internal級別。
  • private:只能在當(dāng)前源文件中使用的實體,稱為私有實體。使用private級別,可以用作隱藏某些功能的實現(xiàn)細(xì)節(jié)。

public為最高級訪問級別,private為最低級訪問級別。

如果你不為代碼中的所有實體定義顯式訪問級別,那么它們默認(rèn)為internal級別。

單元測試目標(biāo)的訪問級別

默認(rèn)情況下只有public級別的實體才可以被其他模塊訪問。然而,如果在引入一個生產(chǎn)模塊時使用@testable注解,然后用帶測試的方式編譯這個生產(chǎn)模塊,單元測試目標(biāo)就可以訪問所有internal級別的實體。

高級運算符

Swift 中的算術(shù)運算符默認(rèn)是不會溢出的。所有溢出行為都會被捕獲并報告為錯誤。如果想讓系統(tǒng)允許溢出行為,可以選擇使用 Swift 中另一套默認(rèn)支持溢出的運算符,比如溢出加法運算符(&+)。所有的這些溢出運算符都是以 & 開頭的。

  • 溢出加法 &+
  • 溢出減法 &-
  • 溢出乘法 &*

位運算符

1)按位取反運算符(~)
2)按位與運算符(&)
3)按位或運算符(|)
4)按位異或運算符(^)
5)按位左移運算符(<<)和按位右移運算符(>>)

類和結(jié)構(gòu)可以為現(xiàn)有的操作符提供自定義的實現(xiàn),這通常被稱為運算符重載(overloading)。

類與結(jié)構(gòu)體也能提供標(biāo)準(zhǔn)單目運算符(unary operators)的實現(xiàn)。單目運算符只有一個操作目標(biāo)。當(dāng)運算符出現(xiàn)在操作目標(biāo)之前時,它就是前綴(prefix)的(比如 -a),而當(dāng)它出現(xiàn)在操作目標(biāo)之后時,它就是后綴(postfix)的(比如 i++)。

要實現(xiàn)前綴或者后綴運算符,需要在聲明運算符函數(shù)的時候在 func 關(guān)鍵字之前指定 prefix 或者 postfix 限定符。

復(fù)合賦值運算符(Compound assignment operators)將賦值運算符(=)與其它運算符進(jìn)行結(jié)合。比如,將加法與賦值結(jié)合成加法賦值運算符(+=)。

還可以將賦值與 prefixpostfix 限定符結(jié)合起來。

不能對默認(rèn)的賦值運算符(=)進(jìn)行重載。只有組合賦值符可以被重載。同樣地,也無法對三目條件運算符 a ? b : c 進(jìn)行重載。

自定義的類和結(jié)構(gòu)體沒有對等價操作符(equivalence operators)進(jìn)行默認(rèn)實現(xiàn),等價操作符通常被稱為“相等”操作符(==)與“不等”操作符(!=)。

新的運算符要在全局作用域內(nèi),使用 operator 關(guān)鍵字進(jìn)行聲明,同時還要指定 prefix、infix 或者 postfix 限定符。

自定義中綴運算符的優(yōu)先級和結(jié)合性

結(jié)合性(associativity)可取的值有left,rightnone。當(dāng)左結(jié)合運算符跟其他相同優(yōu)先級的左結(jié)合運算符寫在一起時,會跟左邊的操作數(shù)進(jìn)行結(jié)合。同理,當(dāng)右結(jié)合運算符跟其他相同優(yōu)先級的右結(jié)合運算符寫在一起時,會跟右邊的操作數(shù)進(jìn)行結(jié)合。而非結(jié)合運算符不能跟其他相同優(yōu)先級的運算符寫在一起。

結(jié)合性(associativity)的默認(rèn)值是 none,優(yōu)先級(precedence)如果沒有指定,則默認(rèn)為 100。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容