前言
SwiftGG 翻譯組的 《The Swift Programming Language》in Chinese 我在 Swift3 的時(shí)候通讀過(guò)一遍,在 Swift4 的時(shí)候只瀏覽了前半部分,并未通讀?,F(xiàn)在 Swift5 準(zhǔn)備再重新讀一遍文檔,把一些遺忘的、易忘的、感覺(jué)值得記下的知識(shí)點(diǎn)梳理一遍,以方便記憶。
基礎(chǔ)部分
一般來(lái)說(shuō),很少需要寫(xiě)類(lèi)型注釋(type animation),如果在聲明常量或者變量時(shí)賦了一個(gè)初始值,
Swift可以推斷出這個(gè)常量或變量的類(lèi)型。如果需要使用
Swift保留關(guān)鍵字相同的名稱(chēng)作為常量或變量名,可以使用反引號(hào)將關(guān)鍵字包圍的方式將其作為名字使用。無(wú)論如何,我們都應(yīng)當(dāng)避免使用關(guān)鍵字作為常量或變量名,除非別無(wú)選擇。當(dāng)遇到一些相關(guān)值得簡(jiǎn)單分組時(shí),元組是很有用的。元組不適合用來(lái)創(chuàng)建復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。如果數(shù)據(jù)結(jié)構(gòu)比較復(fù)雜,不要使用元組,用類(lèi)或者結(jié)構(gòu)體去建模。
if與guard用戶(hù)區(qū)別:在if條件語(yǔ)句中使用常量或變量來(lái)創(chuàng)建一個(gè)可選綁定,僅在if語(yǔ)句的句中body中才能獲取到值。在guard語(yǔ)句中使用常量或變量創(chuàng)建一個(gè)可選綁定時(shí),僅在guard語(yǔ)句外且在語(yǔ)句后才能獲取到值。斷言和先決條件的不同點(diǎn)是,他們什么時(shí)候進(jìn)行狀態(tài)檢測(cè):斷言?xún)H在調(diào)試環(huán)境運(yùn)行,而先決條件則在調(diào)試環(huán)境和生產(chǎn)環(huán)境中運(yùn)行。在生產(chǎn)環(huán)境中,斷言的條件將不進(jìn)行評(píng)估。這意味著我們可以再開(kāi)發(fā)階段使用很多斷言,但是這些斷言再生產(chǎn)環(huán)境都不會(huì)產(chǎn)生影響。
基本運(yùn)算符
在對(duì)負(fù)數(shù)
b求余時(shí),b的符號(hào)會(huì)被忽略。這意味著a % -b和a % b是一樣的結(jié)果。但是-a % b與a % b結(jié)果并不一樣。-
一元正負(fù)號(hào)
+不做任何改變的返回操作數(shù)的值。 雖然一元操作符什么都不會(huì)改變,但當(dāng)使用一元負(fù)號(hào)-來(lái)表達(dá)負(fù)數(shù)時(shí),可以使用一元正好來(lái)表達(dá)正數(shù),使代嗎具有對(duì)稱(chēng)美。let minusSix = -6 let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6 -
如果兩個(gè)元組的元素相同,且長(zhǎng)度相同的話,元組就可以被比較,比較元組大小會(huì)按照從左到右、逐值比較的方式,直到發(fā)現(xiàn)兩個(gè)值不相等時(shí)停止,如果所有值都相等,那么我們就稱(chēng)這一對(duì)元組是相等的。
Swift標(biāo)準(zhǔn)庫(kù)只能比較七個(gè)以?xún)?nèi)元素的元組。如果元組元素超過(guò)七個(gè),則需要自己實(shí)現(xiàn)比較運(yùn)算符。(1, "zebra") < (2, "apple") // true,因?yàn)?1 小于 2 (3, "apple") < (3, "bird") // true,因?yàn)?3 等于 3,但是apple 小于 bird (4, "dog") == (4, "dog") // true,因?yàn)?4 等于 4,dog 等于 dog
- 空合運(yùn)算符
??。ps. 其實(shí)我一直我不清除這個(gè)叫啥名字。。
字符串和字符
-
多行字符串字面量,是由一對(duì)三個(gè)雙引號(hào)包裹著的具有固定順序的文本字符集。也可以在行尾寫(xiě)一個(gè)反斜杠 \ 作為續(xù)行符。
let softWrappedQuotation = """ The White Rabbit put on his spectacles. "Where shall I begin, \ please your Majesty?" he asked. "Begin at the beginning," the King said gravely, "and go on \ till you come to the end; then stop." """
- 關(guān)于
字符串字面量的特殊字符,主要是轉(zhuǎn)義字符、Unicode標(biāo)量。平時(shí)使用較少。還有轉(zhuǎn)義字符反斜杠 \ 的使用。
擴(kuò)展字符串分隔符#。將字符串文字放在擴(kuò)展分隔符中,這樣字符串中的特殊字符將會(huì)被直接包含而不是轉(zhuǎn)移后的效果。如果想要轉(zhuǎn)義字符效果,用等量#包裹住即可。字符串、結(jié)構(gòu)體、枚舉,都是值類(lèi)型。
字符串知識(shí)中,關(guān)于
Unicode,比較零碎,實(shí)際開(kāi)發(fā)中也很少用到,已讀。關(guān)于計(jì)算字符數(shù)量,需要注意的是通過(guò)
count屬性返回的字符數(shù)量并不總是與包含相同自負(fù)的NSString的length屬性相同。NSString的length屬性是利用UTF-16表示的十六位代碼單元數(shù)字,而不是Unicode可擴(kuò)展的字符群集。不同的字符可能會(huì)占用不同數(shù)量的存儲(chǔ)空間,要以要知道字符串中
Character的確定位置,就必須從String開(kāi)頭遍歷每一個(gè)Unicode標(biāo)量到結(jié)尾。因此,Swift的字符串不能整數(shù)integer做索引。子字符串
SubString和String區(qū)別在于性能優(yōu)化上。SubString可以重用原String的內(nèi)存空間,或者另一個(gè)SubString的內(nèi)存空間(String也有同樣的優(yōu)化,但如果兩個(gè)String共享內(nèi)存的話,它們就會(huì)相等)。這一優(yōu)化意味著你在修改String和SubString之前都不需要消耗性能去復(fù)制內(nèi)存。就像前面說(shuō)的那樣,SubString不適合長(zhǎng)期存儲(chǔ) —— 因?yàn)樗赜昧嗽?String的內(nèi)存空間,原String的內(nèi)存空間必須保留直到它的SubString不再被使用為止。
集合類(lèi)型
-
關(guān)于數(shù)組,每天都在用,要強(qiáng)調(diào)的不多。這里說(shuō)三個(gè)方法及區(qū)別:
removeLast(),移除數(shù)組最后一個(gè)元素并返回該元素,數(shù)組必須不為空,否則會(huì)引發(fā)運(yùn)行時(shí)崩潰;popLast(),移除數(shù)組最后一個(gè)可選類(lèi)型的元素,也就是說(shuō),數(shù)組可以為空;dropLast(),移除掉最后幾個(gè)元素,并返回移除后的原數(shù)組。var digitArr = [1,2,3,4,5] var last1 = digitArr.removeLast() var last2 = digitArr.popLast() var remain = digitArr.dropLast(2) print(last1, last2 ?? "-2", remain) // 輸出: 5 4 [1] 集合
Set。用來(lái)存儲(chǔ)相同類(lèi)型并且沒(méi)有順序的值。當(dāng)集合元素順序不重要并且確保每個(gè)元素只出現(xiàn)一次時(shí),可以使用集合而不是數(shù)組??勺约憾x類(lèi)型作為集合的值類(lèi)型,但是定義的類(lèi)型要遵循Hasshable協(xié)議,而Hashable協(xié)議遵循了Equatable協(xié)議,所以定義的類(lèi)型符合這些協(xié)議即可。-
集合提供了一些方法可以高效完成對(duì)集合的操作。
- 使用
intersection(_:)方法根據(jù)兩個(gè)集合的交集創(chuàng)建一個(gè)新的集合。 - 使用
symmetricDifference(_:)方法根據(jù)兩個(gè)集合不相交的值創(chuàng)建一個(gè)新的集合。 - 使用
union(_:)方法根據(jù)兩個(gè)集合的所有值創(chuàng)建一個(gè)新的集合。 - 使用
subtracting(_:)方法根據(jù)不在另一個(gè)集合中的值創(chuàng)建一個(gè)新的集合。
- 使用
-
集合還提供了方法來(lái)判斷集合之間的關(guān)系:
- 使用“是否相等”運(yùn)算符
==來(lái)判斷兩個(gè)集合包含的值是否全部相同。 - 使用
isSubset(of:)方法來(lái)判斷一個(gè)集合中的所有值是否也被包含在另外一個(gè)集合中。 - 使用
isSuperset(of:)方法來(lái)判斷一個(gè)集合是否包含另一個(gè)集合中所有的值。 - 使用
isStrictSubset(of:)或者isStrictSuperset(of:)方法來(lái)判斷一個(gè)集合是否是另外一個(gè)集合的子集合或者父集合并且兩個(gè)集合并不相等。 - 使用
isDisjoint(with:)方法來(lái)判斷兩個(gè)集合是否不含有相同的值(是否沒(méi)有交集)。
- 使用“是否相等”運(yùn)算符
-
字典
Dictionary是一個(gè)無(wú)序集合,存儲(chǔ)鍵值之間的關(guān)系。為了以特定的順序遍歷字典的鍵或值,可以對(duì)字典的keys或values使用sorted()方法。如果想要移除字典中的相關(guān)元素,可以可以使用如下兩種方式:var ages = ["Tom": 20, "jack": 12, "Lilei": 18] ages.removeValue(forKey: "Tom") print(ages) /// ["Lilei": 18, "jack": 12] ages["KK"] = nil print(ages) /// ["Lilei": 18, "jack": 12] ages["jack"] = nil print(ages) /// ["Lilei": 18]
控制流
-
Swift提供了多種流程控制結(jié)構(gòu),包括可以多次執(zhí)行任務(wù)的While循環(huán),基于特定條件選擇執(zhí)行不同代碼分支的if、guard、Switch語(yǔ)句,還有控制流程跳轉(zhuǎn)到其他位置的break和continue語(yǔ)句。Swift還提供了for-in循環(huán),用來(lái)更簡(jiǎn)單的遍歷數(shù)組、字典、區(qū)間、字符串和其他序列類(lèi)型。 -
for-in循環(huán)中,值得注意的有一點(diǎn):stride(from:to:by:)用于半開(kāi)半閉區(qū)間,stride(from:through:by:)用于閉區(qū)間,都是間隔循環(huán)。示例如下:let minutes = 15 let minuteInterval = 5 for tickMark in stride(from: 0, to: minutes, by: minuteInterval) { print("tickMark = ", tickMark) } /// 輸出: 0 5 10 for tickMark in stride(from: 0, through: minutes, by: minuteInterval) { print("tickMark2 = ", tickMark) } /// 輸出: 0 5 10 15 while循環(huán)從計(jì)算一個(gè)條件開(kāi)始,如果條件為true,會(huì)重復(fù)運(yùn)行一段代碼,直到條件變?yōu)?false。repeat-while和while的區(qū)別在于判斷循環(huán)條件之前,先執(zhí)行一次循環(huán)的代碼塊。然后重復(fù)循環(huán)直到條件為false。Switch在Swift中是非常強(qiáng)大、靈活的。支持區(qū)間匹配、元組匹配、值綁定、where條件、復(fù)合型case以及包含相同值綁定的復(fù)合型case等。-
Swift共有五種控制轉(zhuǎn)移語(yǔ)句:
continue,break``fallthrough,return,throw。continue:告訴一個(gè)循環(huán)立即停止本次循環(huán),重新開(kāi)始下一次的循環(huán)。但是不會(huì)離開(kāi)整個(gè)循環(huán)。break:立刻結(jié)束整個(gè)控制流的執(zhí)行。break在循環(huán)中,是結(jié)束該循環(huán)。在Switch中,是結(jié)束該Switch。fallthrough:在switch中使用,該關(guān)鍵字不會(huì)檢查它下一個(gè)將會(huì)落入執(zhí)行的case中的匹配條件。fallthrough簡(jiǎn)單地使代碼繼續(xù)連接到下一個(gè)case中的代碼。這和C語(yǔ)言標(biāo)準(zhǔn)中的switch特性是一樣的。
-
帶標(biāo)簽的語(yǔ)句。這個(gè)我個(gè)人確實(shí)沒(méi)有用到過(guò)。這里記一下。簡(jiǎn)單來(lái)說(shuō),就是給語(yǔ)句命名,然后控制轉(zhuǎn)移語(yǔ)句直接針對(duì)特性語(yǔ)句做處理,下面是代碼:
let finalSquare = 25 var board = [Int](repeating: 0, count: finalSquare + 1) board[03] = +08; board[06] = +11; board[09] = +09; board[10] = +02 board[14] = -10; board[19] = -11; board[22] = -02; board[24] = -08 var square = 0 var diceRoll = 0 gameLoop: while square != finalSquare { diceRoll += 1 if diceRoll == 7 { diceRoll = 1 } switch square + diceRoll { case finalSquare: // 骰子數(shù)剛好使玩家移動(dòng)到最終的方格里,游戲結(jié)束。 break gameLoop case let newSquare where newSquare > finalSquare: // 骰子數(shù)將會(huì)使玩家的移動(dòng)超出最后的方格,那么這種移動(dòng)是不合法的,玩家需要重新擲骰子 continue gameLoop default: // 合法移動(dòng),做正常的處理 square += diceRoll square += board[square] } } print("Game over!") 提前退出語(yǔ)句
guard。-
檢測(cè)
API可用性,只要是針對(duì)不同系統(tǒng)版本的兼容。通用寫(xiě)法:if #available(平臺(tái)名稱(chēng) 版本號(hào), ..., *) { APIs 可用,語(yǔ)句將執(zhí)行 } else { APIs 不可用,語(yǔ)句將不執(zhí)行 }實(shí)際案例展示:
if #available(iOS 10, macOS 10.12, *) { // 在 iOS 使用 iOS 10 的 API, 在 macOS 使用 macOS 10.12 的 API } else { // 使用先前版本的 iOS 和 macOS 的 API }
函數(shù)
-
函數(shù)的可變參數(shù)。一個(gè)可變參數(shù)
variadic parameter可以接受零個(gè)或多個(gè)值。通過(guò)在變量類(lèi)型名后面加入...的方式來(lái)定義可變參數(shù)。傳入值在函數(shù)體中變?yōu)榇祟?lèi)型的一個(gè)數(shù)組。一個(gè)函數(shù)中最多只能有一個(gè)可變參數(shù)。func arithmeticMean(_ numbers: Double...) -> Double { var total: Double = 0 for number in numbers { total += number } return total / Double(numbers.count) } arithmeticMean(1, 2, 3, 4, 5) // 返回 3.0, 是這 5 個(gè)數(shù)的平均數(shù)。 arithmeticMean(3, 8.25, 18.75) // 返回 10.0, 是這 3 個(gè)數(shù)的平均數(shù)。 定義輸入輸出函數(shù),在參數(shù)定義前加
inout關(guān)鍵字即可。注意,只能傳變量給輸入輸出參數(shù),不能傳常量或字面量,因?yàn)檫@些量是不能被修改的。輸入輸出參數(shù)不能有默認(rèn)值,而且可變參數(shù)不能使用inout標(biāo)記。
閉包
-
關(guān)于閉包表達(dá)式的進(jìn)化。雖然越變?cè)胶?jiǎn)單,但是,還是應(yīng)該以清晰明了為主。示例只是對(duì)閉包語(yǔ)法的一個(gè)說(shuō)明:
/// 排序數(shù)組 let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] /// 1.0 版本 func backward(_ s1: String, _ s2: String) -> Bool { return s1 > s2 } var reversedNames = names.sorted(by: backward) print(reversedNames) // reversedNames 為 ["Ewa", "Daniella", "Chris", "Barry", "Alex"] /// 2.0 版本 reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 }) /// 3.0 版本 reversedNames = names.sorted(by: { (s1: String, s2: String) -> Bool in return s1 > s2 } ) /// 4.0 版本 reversedNames = names.sorted(by: { s1, s2 in return s1 > s2 } ) /// 5.0 版本 reversedNames = names.sorted(by: { s1, s2 in s1 > s2 } ) /// 6.0 版本 reversedNames = names.sorted(by: { $0 > $1 } ) /// 最終版 reversedNames = names.sorted(by: >) 閉包是引用類(lèi)型??!
-
在逃逸閉包內(nèi)必須顯示的調(diào)用
self,非逃逸閉包則必須要。所謂逃逸閉包,就是指函數(shù)返回后才會(huì)執(zhí)行的閉包。典型的就是網(wǎng)絡(luò)閉包,在請(qǐng)求結(jié)束后才會(huì)執(zhí)行。還有自動(dòng)閉包autoclosure,但是這個(gè)并不建議使用過(guò)多。override func viewDidLoad() { super.viewDidLoad() someFunctionWithNonescapingClosure { x = 50 } someFunctionWithEscapingClosure { self.x = 100 } someFuncationWithAutoclosureClosure(closure: "Hello") } /// 非逃逸閉包 func someFunctionWithNonescapingClosure(closure: () -> Void) { closure() } /// 逃逸閉包 func someFunctionWithEscapingClosure(closure: @escaping () -> Void) { closure() } /// 自動(dòng)轉(zhuǎn)化閉包 func someFuncationWithAutoclosureClosure(closure: @autoclosure () -> String) { print("\(closure())") }
枚舉
-
令枚舉遵循
CaseIterable協(xié)議。Swift會(huì)生成一個(gè)allCases屬性,用于一個(gè)包含枚舉所有成員的集合。如:enum Beverage: CaseIterable { case coffee, tea, juice } let numberOfChoices = Beverage.allCases.count print("\(numberOfChoices) beverages available") // 打印“3 beverages available” -
遞歸枚舉是一種枚舉類(lèi)型,它由一個(gè)或多個(gè)枚舉成員使用該枚舉類(lèi)型的實(shí)例作為關(guān)聯(lián)值。用遞歸枚舉時(shí),編譯器會(huì)插入一個(gè)間接層??梢栽诿杜e成員前加上
indirect來(lái)標(biāo)識(shí)該成員可遞歸。例如,下面的例子,枚舉存儲(chǔ)了簡(jiǎn)單的算術(shù)表達(dá)式:
enum ArithmeticExpression { case number(Int) indirect case addition(ArithmeticExpression, ArithmeticExpression) indirect case multiplication(ArithmeticExpression, ArithmeticExpression) }也可以再枚舉類(lèi)型開(kāi)頭加上
indirect關(guān)鍵字來(lái)表明它的所有成員都是可遞歸的:indirect enum ArithmeticExpression { case number(Int) case addition(ArithmeticExpression, ArithmeticExpression) case multiplication(ArithmeticExpression, ArithmeticExpression) }
類(lèi)和結(jié)構(gòu)體
-
Swift中機(jī)構(gòu)體和類(lèi)有很多共同點(diǎn),兩者都可以:- 定義屬性有存儲(chǔ)值
- 定義方法用于提供功能
- 定義下標(biāo)操作用于通過(guò)下標(biāo)訪問(wèn)它們的值
- 定義構(gòu)造器用于生成初始值
- 通過(guò)擴(kuò)展增加默認(rèn)實(shí)現(xiàn)以外的功能
- 遵循協(xié)議提供某些標(biāo)準(zhǔn)功能
與結(jié)構(gòu)體相比,類(lèi)還有如下的附加功能:
- 繼承,允許一個(gè)類(lèi)繼承另一個(gè)類(lèi)的特征
- 類(lèi)型轉(zhuǎn)換,允許在運(yùn)行時(shí)檢查和解釋一個(gè)類(lèi)實(shí)例的類(lèi)型
- 析構(gòu)器,允許一個(gè)類(lèi)實(shí)例釋放任務(wù)其所被分配的資源
- 引用計(jì)數(shù),允許對(duì)一個(gè)類(lèi)多次引用
類(lèi)增加的附加功能是以增加復(fù)雜性為代價(jià)的,作為一般準(zhǔn)則,優(yōu)先使用結(jié)構(gòu)體,因?yàn)樗鼈兏菀桌斫?,僅在適當(dāng)或必要時(shí)使用類(lèi)。實(shí)際上,這意味著我們大多數(shù)自定義的數(shù)據(jù)類(lèi)型都應(yīng)該是結(jié)構(gòu)體和枚舉。
-
恒等運(yùn)算符
因?yàn)轭?lèi)是引用類(lèi)型,所以多個(gè)常量或變量幕后可能引用同一個(gè)類(lèi)實(shí)例。對(duì)于結(jié)構(gòu)體和枚舉來(lái)說(shuō),這并不成立,因?yàn)樗麄兌际侵殿?lèi)型,再被賦予到常量、變量或者傳遞到函數(shù)時(shí),其值總是會(huì)被拷貝。
判定兩個(gè)常量或者變量是否引用同一個(gè)類(lèi)實(shí)例又是會(huì)非常有用。為了達(dá)到這個(gè)目的,
Swift提供了兩個(gè)恒等運(yùn)算符,使用這兩個(gè)運(yùn)算符檢測(cè)兩個(gè)常量或者變量是否引用同一個(gè)類(lèi)實(shí)例:- 相同
=== - 不相同
!==
請(qǐng)注意,相同 (用三個(gè)等號(hào)標(biāo)識(shí)
===) 與 相等 (用兩個(gè)等號(hào)表示==) 的不同,相同 表示兩個(gè)類(lèi)類(lèi)型(class type) 的常量或變量是否引用同一個(gè)類(lèi)實(shí)例,相等 用于表示兩個(gè)值是否相等或等價(jià),判定時(shí)要遵循設(shè)計(jì)者定義的評(píng)判標(biāo)準(zhǔn)。 - 相同
屬性
全局的常量或者變量都是延遲計(jì)算的,跟延時(shí)加載存儲(chǔ)屬性相似,不同的地方在于,全局的常量或者變量不需要標(biāo)記
lazy修飾符。而局部范圍的常量或變量從不延遲計(jì)算。類(lèi)型屬性,不論創(chuàng)建多少一個(gè)類(lèi)的類(lèi)實(shí)例,類(lèi)型屬性都只有唯一一份,所有實(shí)例共享該數(shù)據(jù)。使用
static(用于類(lèi)和結(jié)構(gòu)體),或者class(用于類(lèi))關(guān)鍵字作為修飾符。
方法
- 方法是與某些特性類(lèi)型相關(guān)聯(lián)的函數(shù)。譬如實(shí)例方法、類(lèi)方法等。
-
在實(shí)例方法中修改值類(lèi)型
結(jié)構(gòu)體和枚舉都是值類(lèi)型,默認(rèn)情況下,值類(lèi)型的屬性不能在它的實(shí)例方法中被修改。
但是,如果確定需要在某個(gè)特定的方法中修改結(jié)構(gòu)體或者枚舉的屬性,可以為這個(gè)方法選擇 可變
mutating行為,然后就可以在方法內(nèi)部改變它的屬性。在可變方法中可以給
self重新賦值:enum TriStateSwitch { case off, low, high mutating func next() { switch self { case .off: self = .low case .low: self = .high case .high: self = .off } } } var ovenLight = TriStateSwitch.low ovenLight.next() // ovenLight 現(xiàn)在等于 .high ovenLight.next() // ovenLight 現(xiàn)在等于 .off
下標(biāo)
-
下標(biāo)允許通過(guò)在實(shí)例名稱(chēng)后面的方括號(hào)中傳入一個(gè)或者多個(gè)索引值來(lái)對(duì)實(shí)例進(jìn)行查詢(xún)。它的語(yǔ)法類(lèi)似于實(shí)例方法語(yǔ)法和計(jì)算型屬性語(yǔ)法。定義下標(biāo)使用
subscipt關(guān)鍵字,與定義實(shí)例方法類(lèi)似,都是指定一個(gè)或多個(gè)輸入?yún)?shù)和一個(gè)返回類(lèi)型。與實(shí)例方法不同的是,下標(biāo)可以設(shè)定為讀寫(xiě)或只讀。這種行為由getter和setter實(shí)現(xiàn),類(lèi)似計(jì)算型屬性:subscript(index: Int) -> Int { get { // 返回一個(gè)適當(dāng)?shù)?Int 類(lèi)型的值 } set(newValue) { // 執(zhí)行適當(dāng)?shù)馁x值操作 } }
-
實(shí)例下標(biāo)是在特定類(lèi)型的一個(gè)實(shí)例上調(diào)用的下標(biāo)。也可以定義一種在這個(gè)類(lèi)型自身上調(diào)用的下標(biāo)。這種下標(biāo)被稱(chēng)作類(lèi)型下標(biāo)。可以通過(guò)在
subscript關(guān)鍵字之前寫(xiě)下static關(guān)鍵字的方式來(lái)表示一個(gè)類(lèi)型下標(biāo)。類(lèi)類(lèi)型可以使用class關(guān)鍵字來(lái)代替static,它允許子類(lèi)重寫(xiě)父類(lèi)中對(duì)那個(gè)下標(biāo)的實(shí)現(xiàn)。下面的例子展示了如何定義和調(diào)用一個(gè)類(lèi)型下標(biāo):enum Planet: Int { case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune static subscript(n: Int) -> Planet { return Planet(rawValue: n)! } } let mars = Planet[4] print(mars) -
補(bǔ)充一個(gè)
static與class的區(qū)別:-
static可以修飾屬性、函數(shù),可用于類(lèi)或者結(jié)構(gòu)體中。但是被static修飾的對(duì)象不支持重寫(xiě)override。 -
class只用于類(lèi)對(duì)象中,可以重寫(xiě)。
-
繼承
- 在合適的地方,可以通過(guò)使用
super前綴來(lái)訪問(wèn)超類(lèi)版本的方法、屬性或者下標(biāo):- 在方法
someMetho()的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someMethod來(lái)調(diào)用超類(lèi)版本的someMethod()方法。 - 在屬性
someProperty的getter或setter的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)super.someProperty來(lái)訪問(wèn)超類(lèi)版本的someProperty屬性。 - 在下標(biāo)的重寫(xiě)實(shí)現(xiàn)中,可以通過(guò)
super[someIndex]來(lái)訪問(wèn)超類(lèi)版本中相同的下標(biāo)。
- 在方法
- 可以把方法、屬性、下標(biāo)標(biāo)記為
final來(lái)防止它們被重寫(xiě)。只需要在聲明關(guān)鍵字前加上final修飾符即可。也可以在關(guān)鍵字class前添加final修飾符,來(lái)將整個(gè)類(lèi)標(biāo)記為final。這樣的類(lèi)是不可以被繼承的。
構(gòu)造過(guò)程
- 類(lèi)和結(jié)構(gòu)體在創(chuàng)建實(shí)例時(shí),必須為所有存儲(chǔ)屬性設(shè)置合適的初始值。存儲(chǔ)屬性不能處于一個(gè)未知的狀態(tài)。當(dāng)為存儲(chǔ)屬性設(shè)置默認(rèn)值或者在構(gòu)造器中設(shè)置初始值時(shí),他們的值是被直接設(shè)置的,不會(huì)觸發(fā)任何屬性觀察者。
-
關(guān)于 形參命名 和 實(shí)參標(biāo)簽
下面代碼塊中,
fromFahrenheit是實(shí)參標(biāo)簽,fahrenheit是形參命名。struct Celsius { var temperatureInCelsius: Double init(fromFahrenheit fahrenheit: Double) { temperatureInCelsius = (fahrenheit - 32.0) / 1.8 } } 可以再構(gòu)造過(guò)程中的任意點(diǎn)給常量屬性賦值,只要在構(gòu)造過(guò)程結(jié)束時(shí)它設(shè)置成正確的值。一旦長(zhǎng)兩屬性被賦值,它將永遠(yuǎn)不能更改。對(duì)于類(lèi)實(shí)例來(lái)說(shuō),它的常量屬性只能在類(lèi)的構(gòu)造過(guò)程中被修改,不能在子類(lèi)中修改。
結(jié)構(gòu)體如果沒(méi)有定義任何自定義構(gòu)造器,它將自動(dòng)獲得一個(gè) 逐一成員構(gòu)造器(memberwise initializer)。不像默認(rèn)構(gòu)造器,空手存儲(chǔ)型屬性有默認(rèn)值,結(jié)構(gòu)體也會(huì)獲得逐一成員構(gòu)造器。
構(gòu)造器可以調(diào)用其他構(gòu)造器來(lái)完成實(shí)力部分的構(gòu)造過(guò)程。這一過(guò)程成為構(gòu)造器代理。
-
Swift為類(lèi)提供了兩種構(gòu)造器來(lái)確保實(shí)例中所有的存儲(chǔ)型屬性都能獲得初始值,它們被稱(chēng)為指定構(gòu)造器和便利構(gòu)造器。指定構(gòu)造器是類(lèi)中最主要的構(gòu)造器。其中:- 指定構(gòu)造器必須總是 向上代理
- 便利構(gòu)造器必須總是 橫向代理
-
安全檢查的兩段式構(gòu)造過(guò)程展示:
階段 1
- 類(lèi)的某個(gè)指定構(gòu)造器或便利構(gòu)造器被調(diào)用。
- 完成類(lèi)的新實(shí)例的內(nèi)存分配,但此時(shí)內(nèi)存還沒(méi)有被初始化。
- 指定構(gòu)造器確保其所在的類(lèi)引入的所有存儲(chǔ)型屬性都已賦初值。存儲(chǔ)型屬性的內(nèi)存完成初始化。
- 指定構(gòu)造器切換到父類(lèi)的構(gòu)造器,對(duì)其存儲(chǔ)屬性完成同樣的任務(wù)。
- 這個(gè)過(guò)程沿著類(lèi)的繼承鏈一直往上執(zhí)行,直到達(dá)到繼承鏈的最頂部。
- 當(dāng)達(dá)到了繼承鏈的最頂部,而且繼承鏈的最后一個(gè)類(lèi)已經(jīng)確保其所有的存儲(chǔ)型屬性已賦初值,這個(gè)實(shí)例的內(nèi)存被認(rèn)為已經(jīng)完全初始化,此時(shí),階段1完成。
階段 2
- 從繼承鏈的頂部往下,繼承鏈上每個(gè)類(lèi)的指定構(gòu)造器都有機(jī)會(huì)進(jìn)一步自定義實(shí)例。構(gòu)造器此時(shí)可訪問(wèn)
self,修改它的屬性并調(diào)用實(shí)例方法等。 - 最終,繼承鏈中任意的便利構(gòu)造器都有機(jī)會(huì)自定義其實(shí)例和使用
self。
-
可失敗構(gòu)造器的參數(shù)名和參數(shù)類(lèi)型,不能與其他非可失敗構(gòu)造器的參數(shù)名,及參數(shù)類(lèi)型相同。嚴(yán)格來(lái)說(shuō),構(gòu)造器都不支持返回值。因?yàn)闃?gòu)造器本身的作用,只是確保對(duì)象能被正確的構(gòu)造。因此只是用
return nil來(lái)可失敗構(gòu)造器構(gòu)造失敗,而不要用關(guān)鍵字return來(lái)表明構(gòu)造成功。struct Animal { let species: String init?(species: String) { if species.isEmpty { return nil } self.species = species } }
析構(gòu)過(guò)程
- 析構(gòu)器只適用于類(lèi)類(lèi)型,析構(gòu)器是在實(shí)例被釋放前自動(dòng)調(diào)用的。不能主動(dòng)調(diào)用析構(gòu)器。子類(lèi)繼承父類(lèi)的構(gòu)造器,并且在子類(lèi)的構(gòu)造器實(shí)現(xiàn)的最后,父類(lèi)構(gòu)造器會(huì)被自動(dòng)調(diào)用。
可選鏈
- 嗯,就是那個(gè)
?。這里只是說(shuō)明了怎么調(diào)用屬性、方法、下標(biāo)等。
錯(cuò)誤處理
-
Swift中的錯(cuò)誤處理和其他語(yǔ)言中用try、catch、 和throws進(jìn)行異常處理很像。和其他語(yǔ)言(包括Objective-C)的異常處理不同的是,Swift中的錯(cuò)誤處理不涉及解除調(diào)用棧,這是一個(gè)計(jì)算代價(jià)高昂的過(guò)程。就此而言,throw語(yǔ)句的性能特性可以和return語(yǔ)句媲美。
- 為了表示一個(gè)函數(shù)、方法或構(gòu)造器可以拋出錯(cuò)誤,在函數(shù)聲明后加上
throws關(guān)鍵字。一個(gè)標(biāo)有throws的函數(shù)稱(chēng)為throwing函數(shù)。如果這個(gè)函數(shù)指明了返回類(lèi)型,throws關(guān)鍵字要寫(xiě)在返回箭頭->的前面。只有throwing函數(shù)可以傳遞錯(cuò)誤。任何在非throwing函數(shù)內(nèi)部拋出的錯(cuò)誤都只能在函數(shù)內(nèi)部處理。 -
do-catch可以對(duì)錯(cuò)誤進(jìn)行匹配。defer是將代碼的執(zhí)行延遲到當(dāng)前作用域退出之前。
類(lèi)型轉(zhuǎn)換
- 類(lèi)型轉(zhuǎn)換在
Swift中使用as和is操作符實(shí)現(xiàn)。 - 類(lèi)型檢查操作符
is來(lái)檢查一個(gè)實(shí)例是否屬于特定子類(lèi)型。as?或者as!用來(lái)轉(zhuǎn)換。 -
Swift為不確定的類(lèi)型提供了兩種類(lèi)型別名:-
Any標(biāo)識(shí)任何類(lèi)型,包括函數(shù)類(lèi)型。 -
AnyObject可以表示任何類(lèi)類(lèi)型的實(shí)例。
-
嵌套類(lèi)型
- 所謂 嵌套類(lèi)型,是指可以在支持的類(lèi)型中定義嵌套的枚舉、類(lèi)和結(jié)構(gòu)體。要在一個(gè)類(lèi)型中嵌套另一個(gè)類(lèi)型,將嵌套類(lèi)型定義在其外部類(lèi)型的
{ }內(nèi)即可,而且根據(jù)需要可以定義多級(jí)嵌套。(根據(jù)SwiftLint不建議嵌套過(guò)多)
擴(kuò)展
- 擴(kuò)展可以給一個(gè)現(xiàn)有類(lèi)、結(jié)構(gòu)體、枚舉,還有協(xié)議添加新的功能。它擁有在不訪問(wèn)擴(kuò)展類(lèi)型源碼實(shí)現(xiàn)的基礎(chǔ)上就完成功能擴(kuò)展的能力,即逆向建模。但需要注意的是,擴(kuò)展可以添加新的功能,但是不能重寫(xiě)已經(jīng)存在的功能。
Swift中的擴(kuò)展可以:- 添加計(jì)算型實(shí)力屬性和類(lèi)屬性。
- 定義實(shí)例方法和類(lèi)方法。
- 提供新的構(gòu)造器。
- 定義下標(biāo)。
- 定義和使用新的嵌套類(lèi)型。
- 使已經(jīng)存在的類(lèi)型遵循某個(gè)協(xié)議。
- 擴(kuò)展可以添加新的計(jì)算屬性,但是不能添加存儲(chǔ)屬性,或著向現(xiàn)有屬性添加屬性觀察者。
- 擴(kuò)展可以添加便利構(gòu)造器,但是不能添加指定構(gòu)造器。
協(xié)議
- 有時(shí)候需要在方法中改變(或異變)方法所屬的實(shí)例,對(duì)值類(lèi)型,則需要加
mutating關(guān)鍵字。如果在協(xié)議中定義了一個(gè)實(shí)例方法,該方法會(huì)改變遵循該協(xié)議的類(lèi)型的實(shí)例,那么在定義協(xié)議時(shí)需要在方法前添加mutating關(guān)鍵字。這使得結(jié)構(gòu)體和枚舉能夠遵循該協(xié)議并滿(mǎn)足此方法要求。 -
協(xié)議合成,即多個(gè)協(xié)議合一通過(guò)
&符號(hào)結(jié)合起來(lái)。用的并不是很多。 - 協(xié)議擴(kuò)展,可以更優(yōu)雅的實(shí)現(xiàn)
可選協(xié)議。
泛型
請(qǐng)始終以大寫(xiě)字母開(kāi)頭的駝峰命名法來(lái)為類(lèi)型參數(shù)命名,以表明它是一個(gè)占位類(lèi)型,而不是一個(gè)值。
-
類(lèi)型約束指定類(lèi)型參數(shù)必須繼承自指定類(lèi)、遵循特定的協(xié)議或協(xié)議組合。如下:
func someFunction<T: SomeClass, U: SomeProtocol>(someT: T, someU: U) { // 這里是泛型函數(shù)的函數(shù)體部分 } -
關(guān)聯(lián)類(lèi)型
定義一個(gè)協(xié)議時(shí),聲明一個(gè)或多個(gè)關(guān)聯(lián)類(lèi)型作為協(xié)議定義的一部分將會(huì)非常有用。關(guān)聯(lián)類(lèi)型為協(xié)議中某個(gè)類(lèi)型提供了一個(gè)占位符名稱(chēng),其代表的實(shí)際類(lèi)型在協(xié)議被遵循時(shí)才會(huì)指定。關(guān)聯(lián)類(lèi)型通過(guò)
associatedtype關(guān)鍵字來(lái)指定。protocol Container { associatedtype Item mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } }下面用一個(gè)結(jié)構(gòu)體來(lái)遵循這個(gè)協(xié)議:
struct IntStack: Container { // IntStack 的原始實(shí)現(xiàn)部分 var items = [Int]() mutating func push(_ item: Int) { items.append(item) } mutating func pop() -> Int { return items.removeLast() } // Container 協(xié)議的實(shí)現(xiàn)部分 typealias Item = Int mutating func append(_ item: Int) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Int { return items[i] } }或者使用一個(gè)泛型
Stack來(lái)遵循該協(xié)議:struct Stack<Element>: Container { // Stack<Element> 的原始實(shí)現(xiàn)部分 var items = [Element]() mutating func push(_ item: Element) { items.append(item) } mutating func pop() -> Element { return items.removeLast() } // Container 協(xié)議的實(shí)現(xiàn)部分 mutating func append(_ item: Element) { self.push(item) } var count: Int { return items.count } subscript(i: Int) -> Element { return items[i] } }也可以在協(xié)議里給關(guān)聯(lián)類(lèi)型添加約束來(lái)要求遵循的類(lèi)型滿(mǎn)足協(xié)議:
protocol Container { associatedtype Item: Equatable mutating func append(_ item: Item) var count: Int { get } subscript(i: Int) -> Item { get } }或者在關(guān)聯(lián)類(lèi)型約束里使用協(xié)議:
protocol SuffixableContainer: Container { associatedtype Suffix: SuffixableContainer where Suffix.Item == Item func suffix(_ size: Int) -> Suffix } -
** 泛型
Where語(yǔ)句**需要靈活使用
where進(jìn)行條件約束即可。
不透明類(lèi)型
- 雖然使用不透明類(lèi)型作為返回值,看起來(lái)和返回協(xié)議類(lèi)型非常相似,但兩者有個(gè)主要區(qū)別,就是是否需要保持類(lèi)型一致性。一個(gè)不透明類(lèi)型只能對(duì)應(yīng)一種具體的類(lèi)型,即便函數(shù)調(diào)用者并不知道是哪一種類(lèi)型。協(xié)議類(lèi)型可以對(duì)應(yīng)多個(gè)類(lèi)型,只要他們都遵循統(tǒng)一協(xié)議。總得來(lái)說(shuō),協(xié)議類(lèi)型更具靈活性,底層類(lèi)型可以存儲(chǔ)更多的值,而不透明類(lèi)型對(duì)這些底層類(lèi)型有更強(qiáng)的限定性。用法如下:
protocol Shape { func draw() -> String; } struct Quare: Shape { var size: Int func draw() -> String { return size.description; } } class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } /// 返回協(xié)議類(lèi)型 func makeOneQuare() -> Shape { let q1 = Quare(size: 10) print(q1.draw()) return q1; } /// 返回不透明類(lèi)型 func makeSecondQuare() -> some Shape { let q2 = Quare(size: 10) print(q2.draw()) return q2; } } - 說(shuō)一下自己的看法吧:不透明類(lèi)型是可以被協(xié)議類(lèi)型替代使用的,這個(gè)就好像
weak、unowned兩個(gè)關(guān)鍵詞一樣,我們有知道區(qū)別的必要性,但是即使只用weak,就可以解決循環(huán)引用的問(wèn)題了??赡苷娴挠兄荒苁褂?unowned的情況,如果以后遇到,會(huì)在這里補(bǔ)充。
自動(dòng)引用計(jì)數(shù)
- 引用計(jì)數(shù)僅僅用于類(lèi)的實(shí)例。結(jié)構(gòu)體和枚舉都是值類(lèi)型,不是引用類(lèi)型,也不是通過(guò)引用的方式存儲(chǔ)和傳遞。
-
弱引用不會(huì)對(duì)其引用的實(shí)例保持強(qiáng)引用,因而不會(huì)阻止
ARC銷(xiāo)毀被引用的實(shí)例。這個(gè)特性阻止了引用變?yōu)檠h(huán)引用。關(guān)鍵字weak。另外,當(dāng)ARC設(shè)置弱引用為nil時(shí),屬性觀察不會(huì)被觸發(fā)。 - 和弱引用類(lèi)似,無(wú)主引用不會(huì)牢牢保持引用的實(shí)例。和弱引用不同的是,無(wú)主引用在其他實(shí)例有相同或更長(zhǎng)聲明周期時(shí)使用。關(guān)鍵字是
unowned。無(wú)主引用通常都被期望有值。不過(guò)ARC無(wú)法再實(shí)例被銷(xiāo)毀后將無(wú)主引用設(shè)為nil,因?yàn)榉强蛇x類(lèi)型的實(shí)例不允許被置為nil。并且,使用無(wú)主引用,必須確保引用始終指向一個(gè)未被銷(xiāo)毀的實(shí)例。如果在該實(shí)例被銷(xiāo)毀后,訪問(wèn)該實(shí)例的無(wú)主引用,會(huì)觸發(fā)運(yùn)行時(shí)崩潰。 - 閉包和類(lèi)相似,都是引用類(lèi)型。循環(huán)引用可以通過(guò)弱引用或者無(wú)主引用來(lái)解決。
內(nèi)存安全
1. 內(nèi)存訪問(wèn)沖突的實(shí)質(zhì):
- 內(nèi)存訪問(wèn)沖突時(shí),要考慮內(nèi)存訪問(wèn)上下文的三個(gè)性質(zhì):訪問(wèn)是讀還是寫(xiě),訪問(wèn)的時(shí)長(zhǎng),以及訪問(wèn)的地址。特別是,沖突會(huì)發(fā)生在有兩個(gè)訪問(wèn)符合下列情況時(shí):
- 至少有一個(gè)是寫(xiě)訪問(wèn)
- 他們的訪問(wèn)是同一個(gè)內(nèi)存地址
- 他們的訪問(wèn)在時(shí)間線上有部分的重疊。
2. Swift 中兩種長(zhǎng)期訪問(wèn)類(lèi)型:
-
In-Out參數(shù)的訪問(wèn)沖突。 - 結(jié)構(gòu)體
mutating方法里。
3. 這個(gè)小節(jié)里舉的例子值得回頭再看看。
主要是針對(duì)長(zhǎng)期內(nèi)存訪問(wèn)的分析,和解決方法。
訪問(wèn)控制
1. 訪問(wèn)級(jí)別
Swift 為代碼中的實(shí)體提供了五種不同的訪問(wèn)級(jí)別:
-
open和public級(jí)別可以讓實(shí)體被同一模塊的所有實(shí)體訪問(wèn)。在模塊外也可以通過(guò)導(dǎo)入該模塊來(lái)訪問(wèn)原文件里的所有實(shí)體。通常情況下,使用open或者public來(lái)定義模塊對(duì)外訪問(wèn)接口。open只能作用于類(lèi)或者類(lèi)的成員,它和public的區(qū)別主要在于open限定的類(lèi)或者類(lèi)的成員能夠在模塊外被繼承和重寫(xiě)。將類(lèi)的訪問(wèn)級(jí)別顯示指定為open表明已經(jīng)設(shè)計(jì)好了類(lèi)的代碼,并且充分考慮到了這個(gè)類(lèi)在其他模塊作為父類(lèi)時(shí)的影響。 -
internal級(jí)別讓實(shí)體被同一模塊源文件的任何實(shí)體訪問(wèn),但是不能被模塊外的實(shí)體訪問(wèn)。通常情況下,某個(gè)實(shí)體只在應(yīng)用程序或者框架內(nèi)部使用,可以將其設(shè)置為internal級(jí)別。同時(shí),這個(gè)也是默認(rèn)訪問(wèn)級(jí)別。 -
fileprivate限制實(shí)體只能在其定義的文件內(nèi)部訪問(wèn)。如果功能代碼的實(shí)現(xiàn)細(xì)節(jié)只需要在文件內(nèi)部訪問(wèn)時(shí),可以使用fileprivate來(lái)將其隱藏。 -
private限制實(shí)體只能在其定義的作用域,以及同一文件的extension中訪問(wèn)。非同一個(gè)源文件的extension,也是無(wú)法訪問(wèn)的。
以上, open 的訪問(wèn)級(jí)別最高,限制最少。private 的訪問(wèn)級(jí)別最低,限制最多。
2. 訪問(wèn)級(jí)別規(guī)則
Swift 中訪問(wèn)級(jí)別遵循一個(gè)原則:實(shí)體不能定義在具有更低級(jí)別訪問(wèn)的實(shí)體中。例如:
- 一個(gè)
public的變量,其所在類(lèi)型的訪問(wèn)級(jí)別不能是internal、fileprivate或者private。因?yàn)闊o(wú)法保證變量的類(lèi)型在使用變量的地方也具有訪問(wèn)權(quán)限。 - 函數(shù)的訪問(wèn)級(jí)別不能高于它的參數(shù)類(lèi)型和返回類(lèi)型的訪問(wèn)級(jí)別。因?yàn)檫@樣就會(huì)出現(xiàn)函數(shù)可以在任何地方被訪問(wèn),而參數(shù)和返回類(lèi)型不可以的情況。
注意,即使違反上面的規(guī)則,正常情況下,也不會(huì)編譯或者運(yùn)行錯(cuò)誤…
高級(jí)運(yùn)算符
開(kāi)發(fā)中比較少需要使用高級(jí)運(yùn)算符,這里留著記錄,具體使用時(shí)在參考,點(diǎn)擊標(biāo)題即可。
1. 位運(yùn)算符
-
按位取反運(yùn)算符
Bitwise NOT Operator- 按位取反運(yùn)算符
~對(duì)一個(gè)數(shù)值的全部比特位進(jìn)行取反 - 按位取反運(yùn)算符是一個(gè)前綴運(yùn)算符,直接放在運(yùn)算數(shù)之前,并且他們之間不能添加任何空格。
let age = 18 let invertAge = ~age print(invertAge) // -19 - 按位取反運(yùn)算符
-
按位與運(yùn)算符
Bitwise AND Operator- 按位與運(yùn)算符
&對(duì)兩個(gè)數(shù)的比特位進(jìn)行合并。它返回一個(gè)新的數(shù)。只有當(dāng)兩個(gè)數(shù)的全部對(duì)應(yīng)為都為1的時(shí)候,新數(shù)的對(duì)應(yīng)位才為1。
let one = 10 let sec = 10 let third = 20 let and1 = one & sec let and2 = one & third print(and1, and2) // 10 0 - 按位與運(yùn)算符
-
按位或運(yùn)算符
Bitwise OR Operaor- 按位或運(yùn)算符
|可以對(duì)兩個(gè)數(shù)的比特位進(jìn)行比較。它返回一個(gè)新的數(shù),只要兩個(gè)數(shù)的對(duì)應(yīng)位中任意一個(gè)為1,新數(shù)的對(duì)應(yīng)位就為1。
- 按位或運(yùn)算符
-
按位異或運(yùn)算符
Bitwise XOR Operator- 按位異或運(yùn)算符,或稱(chēng)排外的運(yùn)算符
^,可以對(duì)兩個(gè)數(shù)的比特位進(jìn)行比較。它返回一個(gè)新的數(shù),當(dāng)兩個(gè)數(shù)的對(duì)應(yīng)為不相同時(shí),新數(shù)的對(duì)應(yīng)位就為1,對(duì)應(yīng)位相同時(shí),則為0。
- 按位異或運(yùn)算符,或稱(chēng)排外的運(yùn)算符
-
按位左移、按位右移運(yùn)算符
Bitwise Left Right Shift Operators- 按位左移運(yùn)算符
<<和按位右移運(yùn)算符>>可以對(duì)一個(gè)數(shù)的所有位指定位數(shù)的左移或者右移,但是需要遵循下面定義的規(guī)則。 - 對(duì)一個(gè)數(shù)進(jìn)行按位左移或者按位右移,相當(dāng)于對(duì)這個(gè)數(shù)進(jìn)行乘以
2或者除以2的運(yùn)算。將一個(gè)整數(shù)左移一位,等價(jià)于將這個(gè)數(shù)乘以2。同樣的,將一個(gè)整數(shù)右移一位,等價(jià)于將這個(gè)數(shù)除以2。 - 無(wú)符號(hào)整數(shù)的移位運(yùn)算(簡(jiǎn)單)
- 有符號(hào)整數(shù)的移位運(yùn)算(復(fù)雜)
- 按位左移運(yùn)算符
2. 溢出運(yùn)算符
- 溢出加法
&+ - 溢出減法
&- - 溢出乘法
&*
3. 優(yōu)先級(jí)和結(jié)合性
運(yùn)算時(shí),加上必要的括號(hào),更具可讀性。
4. 運(yùn)算符函數(shù)
類(lèi)和結(jié)構(gòu)體可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn),這通常被稱(chēng)為 運(yùn)算符重載 。
- 前綴和后綴運(yùn)算符,如
-a、b! - 符合賦值運(yùn)算符,如
=、+= - 等價(jià)運(yùn)算符,如
==、!=
5. 自定義運(yùn)算符
自定義運(yùn)算符的優(yōu)先級(jí)。
后記
本來(lái)是想一星期補(bǔ)完的, 結(jié)果斷斷續(xù)續(xù)持續(xù)了兩周多。這里僅僅是記錄自己日常中容易忽視的,或者不太常用的一些點(diǎn)。語(yǔ)言參考只是讓我們對(duì)這個(gè)語(yǔ)言有個(gè)大概的了解,想要加深對(duì) Swift 的理解,還是應(yīng)該更多的去看優(yōu)秀的源碼,自己動(dòng)手去實(shí)踐和總結(jié)。