Swift語言指南(九)--基本運算子

weixin_34126215發表於2014-06-16
原文:Swift語言指南(九)--基本運算子

運算子(operator)是用來檢查,改變或合併值的一種特殊符號或短語。例如,加號運算子讓兩個數字相加(如:let i = 1 + 2),還有些更復雜的運算子,如邏輯與運算子(&&)(如:if enteredDoorCode && passedRetinaScan)和自增運算子(++i)(將 i 的值加 1 的便捷寫法)。

Swift 支援標準C語言的大多數運算子,並且改進了一些特性以規避常見的程式碼錯誤。賦值運算子(=)是沒有返回值的,這樣是為了避免在使用等於運算子(==)時誤用了賦值運算子(=)。算術運算子(+-*/% 等等)會偵測並阻止值溢位,可避免在運算時超出儲存型別的值域範圍(比實際運算結果大或小,或不精準--Joe.Huang)。如果需要支援溢位行為,可以選用 Swift 的溢位運算子,詳情可見 溢位運算子(後面章節譯到)。

與C語言不同的是,Swift 允許對浮點數求餘(%)。Swift 還提供了C語言所沒有的兩個區間運算子(a..b和a...b),作為表示值域範圍的便捷寫法。

本章介紹 Swift 中的常用運算子。高階運算子 (後面章節譯到) 一章涵蓋了 Swift 中的高階運算子,並講解了如何自定義運算子,以及讓標準運算子支援自定義型別的運算。

 

運算子術語

運算子分為一元,二元,三元運算子:

· 一元運算子unary operator)對單個目標進行運算(如 -a)。一元運算子字首unary prefix operator)緊跟運算目標之前(如 !b),而一元運算子字尾unary postfix operator)則緊跟運算目標之後(如 i++)。

· 二元運算子binary operator)對兩個目標進行運算(如 2 + 3),它們屬於中綴infix)運算子,因為(運算子號)出現在兩個運算目標之間。

· 三元運算子ternary operator)對三個目標進行運算。與 C 語言一樣,Swift 只有一個三元運算子:三元條件運算子( a ? b : c)。

運算子操作的值稱為運算元operands)。在表示式 1 + 2 中,+ 符號是二元運算子,它的兩個運算元為值 1與值 2

 

賦值運算子

賦值運算子assignment operator,a = b)用 b 的值初始化或更新 a 的值:

1 let b = 10
2 var a = 5
3 a = b
4 // a is now equal to 10
5 //a現在等於10

如果賦值語句的右側是一個包含多個值的元組,元組的元素可一次性用多個常量或變數分解提取出來(上一章講解元組時提到過分解元組值的方法--Joe.Huang):

1 let (x, y) = (1, 2)
2 // x is equal to 1, and y is equal to 2
3 //x等於1,y等於2

與 C 或 Objective-C 語言的賦值運算子不同,Swift 語言的賦值運算子本身沒有返回值。因此下面的語句不正確:

1 if x = y {
2     // this is not valid, because x = y does not return a value
3     // 這是無效的,因為 x = y 不會返回一個值 (x==y才可以,--Joe.Huang)
4 }

該特性可避免在使用等於運算子(==)時誤用了賦值運算子(=)。通過否認 if x = y 的有效性,Swift 將幫助你規避程式碼中出現這樣的錯誤。

 

算術運算子

Swift支援對所有數字型別使用四種標準算術運算子:

· 加:+

· 減:-

· 乘:*

· 除:/

1 1 + 2       //  等於3
2 5 - 3       //  等於2
3 2 * 3       //  等於6
4 10.0 / 2.5  //  等於4.0

與 C / Objective-C 語言的算術運算子不同,Swift 的算術運算子預設不允許值溢位。如果需要支援溢位行為,可以選用 Swift 的溢位運算子(如,a &+ b),詳情可見 溢位運算子(後面章節譯到)。

加號運算子也支援 String 拼接:

"hello, " + "world"  // 等於 "hello, world"

可以將兩個 Character (字元,Unicode字元--Joe.Huang)值相加,或將一個 Character 值與一個 String 值相加,得到新的 String 值:

1 let dog: Character = ""
2 let cow: Character = ""
3 let dogCow = dog + cow
4 // dogCow 等於 ""

 詳見 字元與字串拼接 (後面章節譯到):

 

求餘運算子

求餘運算子remainder operatora % b)求出 a 包含多少個 b,並返回剩餘的值(即整除後的餘數 remainder)。

 注:

求餘運算子(%)在其他語言中也稱作求模運算子modulo operator)。但對負數的運算結果表明:Swift 語言的實現是嚴格的求餘操作,而非求模操作。

求餘運算子的原理如下。 要計算 9 % 4,首先要求出 9 裡面包含多少個 4

 

如圖所示,9 裡面包含兩個 4,餘數是 1 (橙色部分)。 

Swift中的寫法如下:

9 % 4  //等於 1

要求出 a % b 的結果,% 運算子會計算下面的等式,並將餘數作為輸出結果返回:

a = (b × some multiplier) + remainder

其中 some multipliera 中能裝下 b 的最大數目。

94 代入等式:

9 = (4 × 2) + 1

a 為負數時,求餘方法不變:

-9 % 4   // 等於 -1

-94 代入等式:

-9 = (4 × -2) + -1

得到的餘數值為-1

b 為負值(-b)時,b 的負號將被忽略。因此 a % ba % -b 總是返回相同的結果。

 

浮點數的求餘計算

與 C / Objective-C 語言的餘數運算子不同,Swift 的餘數運算子還能對浮點數進行求餘計算:

8 % 2.5   // equals 0.5

上例中,8 除以 2.5 等於 3,餘數為 0.5,因此餘數運算子返回 Double 型的值 0.5

 

自增與自減運算子

與 C 語言類似,Swift 也提供了自增運算子++)與自減運算子--),作為將數字變數的值加上或減去 1 的便捷寫法。任何整型或浮點型的變數都可以使用這兩個運算子。

1 var i = 0
2 ++i      // i 現在等於 1

每次呼叫 ++i 時,i 的值就會增加 1。本質上,++i 就是 i = i + 1 的便捷寫法。類似地,--i 也相當於 i = i - 1

++-- 兩對符號可以作為字首或字尾運算子使用。++ii++ 均可用來將 i 的值加 1。類似地,--i i-- 均可用來將 i 的值減去 1

注意,這些運算子不僅會改變 i 的值,還會返回一個值。如果你只需要將自增或自減後的值存放在 i 中,那你可以忽略運算子的返回值。但如果你確實要用到返回值,要注意字首及字尾運算子返回值的差異,規則如下:

· 如果運算子在變數名前面,先改變它的值,再返回其值。

· 如果運算子在變數名後面,先返回原值,再改變它的值。

如例:

1 var a = 0
2 let b = ++a
3 // a 和 b 現在都等於 1,即改變a的值,再返回
4 let c = a++
5 // a 現在等於 2, 但 c 還是自增前的值 1,即先返回的a的原值,再改變其值

在上例中,let b = ++a 先增加 a 的值(加1),然後才返回它的值。因此 ab 都等於新的值 1

但是,let c = a++ 先返回 a 的原值(加1之前的值)然後才增加 a 的值。即 c 得到了原值 1,然後 a 被更新為新值 2

除非你需要利用 i++ 的這一特性,建議你在所有情況下都使用 ++i--i,因為它們先修改 i 再返回修改後的值的動作更符合邏輯。

 

一元減號運算子

數值前加上字首 - ,這個字首運算子 - 就稱為一元減號運算子:

1 let three = 3
2 let minusThree = -three       // minusThree 等於 -3
3 let plusThree = -minusThree   // plusThree 等於 3, 或等於 "減去 minusThree"

一元減號運算子(-)緊靠所要操作的值之前,無需任何空格。

 

一元加號運算子

一元加號運算子(+)直接返回所操作的值,不作任何處理:

1 let minusSix = -6
2 let alsoMinusSix = +minusSix  // alsoMinusSix 等於 -6

儘管一元加號運算子實際上不作任何運算,程式碼中仍然可以用它(提供語義資訊,一元減號運算子表示負數,一元加號運算子表示正數--Joe.Huang)與表示負數的一元減號運算子形成對比。

 

複合賦值運算子

與 C 語言類似,Swift 也提供複合賦值運算子compound assignment operator將賦值運算子(=)與其他運算組合起來使用。例如加法賦值運算子(addition assignment operator+=):

1 var a = 1
2 a += 2
3 // a 等於 3

上例中的表示式 a = a + 2 簡寫為 a += 2,加法和賦值兩項操作組合為一個單項操作,執行時非常高效。

注:

複合賦值操作沒有返回值,即,你不能寫:let b = a += 2,這一操作與前面所提到的自增自減操作是不同的。

複合賦值運算子的完整列表可在 表示式 一章中找到(後面章節譯到)。

 

比較運算子

Swift支援標準C 的比較運算子:

      等於   (a == b)
   不等於   (a != b)
      大於   (a > b)
      小於   (a < b)
 大於等於  (a >= b)
 小於等於  (a <= b)

注:

Swift還提供了恆等(===)和不恆等(!==)兩個鑑別運算子,你可以用它測試兩個物件是否引用了同一個物件例項。更多詳情請參考 類和結構 一章(後面章節譯到)。

每個比較運算子都會返回一個 Bool 值,檢測表示式是否成立:

1 1 == 1   // true, 因為 1 等於 1
2 2 != 1   // true, 因為 2 不等於 1
3 2 > 1    // true, 因為 2 大於 1
4 1 < 2    // true, 因為 1 小於 2
5 1 >= 1   // true, 因為 1 大於等於 1
6 2 <= 1   // false, 因為 2 大於等於 1

比較運算子常見於條件表示式中,如 if 條件句:

1 let name = "world"
2 if name == "world" {
3     println("hello, world")
4 } else {
5     println("I'm sorry \(name), but I don't recognize you")
6     //輸出(”對不起\name,我不認識你“)
7 }
8 // prints "hello, world", because name is indeed equal to "world"
9 //輸出 "hello world",因為 name 確實等於"world"

if 語句的更多介紹,詳見 流程控制 一章(後面章節譯到)。

 

三元條件運算子

三元運算子是一種特殊運算子,由三個部分組成,表現形式為:question ? answer1 : answer2。它是一種求值簡寫:根據 question 是否成立,從兩個表示式中取出一個並求值。

如果 question 成立,則計算 answer1 的結果並返回其值;否則計算 answer2 並返回其值。

三元條件運算子是如下程式碼的縮寫:

1 if question {
2     answer1
3 } else {
4     answer2
5 }

下面的例子將計算表格某行的畫素高度。如果該行有表頭,則行高應比內容高度高 50 個畫素;如果沒有表頭,則只高出 20 個畫素:

1 let contentHeight = 40
2 let hasHeader = true
3 let rowHeight = contentHeight + (hasHeader ? 50 : 20)
4 // rowHeight(行高) 等於 90

上例便是如下程式碼的縮寫:

1 let contentHeight = 40
2 let hasHeader = true
3 var rowHeight = contentHeight
4 if hasHeader {
5     rowHeight = rowHeight + 50
6 } else {
7     rowHeight = rowHeight + 20
8 }
9 // rowHeight(行高) 等於 90

使用三元條件運算子的例子說明,可以僅用一行程式碼就將行高設為正確的值。這比(不用三元運算子的)第二個例子簡潔得多,並且行高(rowHeight)無需定義為變數,因為不再需要用 if 語句修改其值。

三元條件運算子提供了二選一的高效寫法。但使用三元條件運算子應小心。如果過度使用,其簡明性可能導致程式碼可讀性差。應避免將多個三元條件運算子組合在同一個語句中。

 

區間運算子

Swift有兩個區間運演算法,是表示值域的簡便寫法。

 

閉區間運算子

區間運算子(a...b)定義了 ab 的區間範圍,包括 a 在內。

閉區間運算子在需要遍歷某區間內所有的值時很有用,如在 for-in 迴圈中使用:

1 for index in 1...5 {
2     println("\(index) times 5 is \(index * 5)")
3     //輸出("\(index)乘以 5 得 (\index * 5)")
4 }
5 // 1 乘以 5 得 5
6 // 2 乘以 5 得 10
7 // 3 乘以 5 得 15
8 // 4 乘以 5 得 20
9 // 5 乘以 5 得 25

for-in 語句的更多介紹,詳見 流程控制 一章(後面章節譯到)。

 

半閉區間運算子

半閉區間運算子(a..b)定義了從 ab 的區間,但 b 不包括在內。說它是半閉區間,是因為第一個值包含在區間內,但最後一個值在區間外。

半閉區間在處理從 0 開始計數的列表時有用,如遍歷陣列,可從 0 數到列表的長度(但不包括長度值本身):

1 let names = ["Anna", "Alex", "Brian", "Jack"]
2 let count = names.count
3 for i in 0..count {
4     println("Person \(i + 1) is called \(names[i])")
5 }
6 // Person 1 名字是 Anna
7 // Person 2 名字是 Alex
8 // Person 3 名字是 Brian
9 // Person 4 名字是 Jack

注意,陣列包含四個元素,但因為是半閉區間,所以 0..count 只數到 3(陣列中最後一個元素的索引號)。陣列更多資訊詳見 陣列 一章(後面章節譯到)

 

邏輯運算子

邏輯運算子是對布林邏輯值 truefalse 的組合操作,Swift 支援 C 及其衍生語言的三種標準邏輯運算子:

· 邏輯非(!a

· 邏輯與(a && b

· 邏輯或(a || b

邏輯非運算子

邏輯非運算子對布林值取反,即 true 變成 falsefalse 變成true

邏輯非運算子是一個字首運算子,緊跟在所操作值的前面,沒有任何空格符。可以理解為"非",如下例:

1 let allowedEntry = false
2 if !allowedEntry {
3     println("ACCESS DENIED")
4 }
5 // prints "ACCESS DENIED"
6 //輸出”ACCESS DENIED“

程式碼中的 if !allowedEntry 可以理解為“如果不允許進入”。隨後的下一行程式碼僅當“不允許進入”成立時才會執行;即 allowedEntry 為 false 時才執行。

如上例,布林值常量及變數的名稱應謹慎選擇命名,方可確保程式碼簡明又具可讀性,同時也應避免使用雙重否定或引起混淆的邏輯語句。

 

邏輯與運算子

a && b)構造這樣的邏輯表示式:運算子兩側的值均為 true,整個表示式的求值結果才為 true

 

如果有一個值為 false,整個表示式便為 false。事實上,如果第一個值false,第二個值將不執行求值運算,因為無論它為何值,整個表示式的值都不可能等於 true。這也被稱為短路求值short-circuit evaluation)。

下面的例子驗證兩個值,當兩個值都為 true 時才能訪問:

 

1 let enteredDoorCode = true
2 let passedRetinaScan = false
3 if enteredDoorCode && passedRetinaScan {
4     println("Welcome!")
5 } else {
6     println("ACCESS DENIED")
7 }
8 // prints "ACCESS DENIED"  輸出"ACCESS DENIED"

 

邏輯或運算子

a || b)屬於中綴運算子,由兩個連續的豎線構成。它用來構造這樣的表示式:當兩個值中有一個為 true時,整個表示式為 true

與前面的邏輯與運算子一樣,邏輯或運算子在檢測它的兩個表示式時,也使用“短路求值”法。只要邏輯或表示式左側為 true,其右側將不執行求值運算,因為這時右側的值對整個表示式的結果不再有影響。

下例中,第一個 Bool 值(hasDoorKey)為 false,但第二個值(knowOverridePassword)為 true。因為有一個值為 true,所以整個表示式的求值結果也為 true,因此允許訪問:

1 let hasDoorKey = false
2 let knowsOverridePassword = true
3 if hasDoorKey || knowsOverridePassword {
4     println("Welcome!")
5 } else {
6     println("ACCESS DENIED")
7 }
8 // prints "Welcome!"  輸出"Welcome!"

 

組合使用邏輯運算子

可以將多個邏輯運算子組合起來構成一個較長的複合表示式。

1if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
2     println("Welcome!")
3 } else {
4     println("ACCESS DENIED")
5 }
6 // prints "Welcome!"  輸出"Welcome!"

本例使用多個 &&|| 運算子構成一條較長的複合表示式。不過,&&|| 運算子操作的仍然是兩個值,因此該組合表示式實際上是由三個較短的表示式連立而成。它可以這樣理解:

如果我們輸入了正確的門禁密碼、並且通過了視網膜掃描;或者如果我們有門鑰匙;或者如果我們知道緊急的備用密碼,則允許訪問。

根據 enteredDoorCodepassedRetinaScanhasDoorKey 三個常量推算,前兩個小表示式的值均為 false。不過我們知道緊急的備用密碼(knowsOverridePassword 為 true),因此整個複合表示式的求值結果仍然為 true


顯式括號

有時(從語法來看)括號並不是必需的,但加上括號卻很有用,它可以讓複雜表示式的易於閱讀。 在上例中,為組合表示式的第一部分加上括號,可使其意圖更明顯:

1 if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
2     println("Welcome!")
3 } else {
4     println("ACCESS DENIED")
5 }
6 // prints "Welcome!"  //輸出"Welcome!"

括號將前兩個值與其他值分隔開來,使其作為整體邏輯中的一種可選狀態的意思更加明顯。組合表示式的結果不會改變,但對讀者而言,整體意圖更加清晰。可讀性總是優先於簡潔性;應儘可能在合適的地方使用括號,使你的邏輯更加明晰。

 

 

謝謝,Swifter-QQ群:362232993,同好者進~ 

Fork:https://github.com/Joejo/Swift-lesson-for-chinese

 

 

 

 

相關文章