目錄
- 1、術語
- 2、賦值運算符(a = b)
- 3、算術運算符(+、-、*、/)
- 3.1、余數運算符(%)
- 3.2、一元負號運算符(-a)
- 3.3、一元正號運算符(+a)
- 4、復合賦值運算符(+=)
- 5、比較運算符(==、!=、>、<、>=、<=)
- 6、三元條件運算符(a>b ? c : d)
- 7、空合并運算符(a ?? b)
- 8、區間運算符
- 8.1、閉區間運算符(a...b)
- 8.2、半開區間運算符(a..<b)
- 8.3、單側區間(names[2...])
- 8、邏輯運算符(&&、||、!)
- 8.1、邏輯非運算符(!)
- 8.2、邏輯與運算符(&&)
- 8.3、邏輯或運算符(||)
- 8.4、組合邏輯運算符
- 8.5、顯式括號
基本運算符執行賦值、算術和比較等操作。
運算符是一種特殊的符號或短語,用于檢查、更改或組合值。例如,加法運算符(+
)將兩個數字相加,如 let i = 1 + 2
,邏輯與運算符(&&
)組合兩個布爾值,如 if enteredDoorCode && passedRetinaScan
。
Swift 支持類似 C 等你已所熟知的語言中的運算符,并改進了幾個功能,以消除常見的編碼錯誤。賦值運算符(=
)不返回值,以防止它被誤用時等于運算符(==
)被意外使用。算術運算符(+
、-
、*
、/
、%
等)檢測并禁止值溢出,以避免在處理超出存儲它們的類型允許值范圍的較大或較小數字時出現意外結果。
Swift 還提供了 C 語言中沒有的區間運算符,如 a..<b
和 a...b
,作為表達值范圍的快捷方式。
本章介紹了 Swift 中的常見運算符。
1、術語
運算符可以是一元、二元或三元:
- 一元運算符:作用于單個目標(如
-a
)。一元前置運算符緊跟在其目標之前(如!b
),一元后置運算符緊跟在其目標之后(如c!
)。 - 二元運算符:作用于兩個目標(如
2 + 3
),是中置的,因為它們出現在兩個目標之間。 - 三元運算符:作用于三個目標。與 C 一樣,Swift 只有一個三元運算符,即三元條件運算符(
a ? b : c
)。
運算符影響的值稱為操作數。在表達式 1 + 2
中,+
符號是一個中置運算符,它的兩個操作數是值 1
和 2
。
2、賦值運算符(a = b)
賦值運算符:(a = b
)用 b
的值初始化或更新 a
的值:
let b = 10
var a = 5
a = b
// a 現在等于 10
如果賦值運算符的右側是一個包含多個值的元組,可以將其元素同時分解為多個常量或變量:
let (x, y) = (1, 2) // x 等于 1, y 等于 2
與 C 和 Objective-C 中的賦值運算符不同,Swift 中的賦值運算符本身不返回值。以下語句無效:
if x = y { // 這是無效的,因為 x = y 不返回值。
}
因為 Swift 語言規定 if x = y
這種寫法是無效的,這個特性可以防止不小心使用賦值運算符(=) 而非等于運算符(==)。Swift 幫助你避免代碼中出現這種錯誤。
3、算術運算符(+、-、*、/)
Swift 為所有數值類型支持四種標準算術運算符:
- 加法(
+
) - 減法(
-
) - 乘法(
*
) - 除法(
/
)
1 + 2 // 等于 3
5 - 3 // 等于 2
2 * 3 // 等于 6
10.0 / 2.5 // 等于 4.0
Swift 的算術運算符與 C 和 Objective-C 中的不同,默認情況下不允許值溢出。您可以選擇使用 Swift 的溢出運算符(如 a &+ b
)來啟用值溢出行為。
加法運算符也支持 String
拼接:
"hello, " + "world" // 等于 "hello, world"
3.1、余數運算符(%)
余數運算符:(a % b
)計算出 b
在 a
中能容納多少個倍數,并返回剩余的值(稱為余數)。
注意: 需要注意的是,盡管余數運算符在其他語言中也被稱為模運算符, 但在 Swift 中對負數的處理與模運算符有所不同。
讓我們來看看余數運算符是如何工作的。 要計算 9 % 4
,首先要確定 9
中可以包含多少個 4
:
我們可以在 9
中容納兩個 4
,剩余的是 1
(用橙色表示)。
在 Swift 中,這可以寫作:
9 % 4 // 等于 1
為了確定 a % b
的答案,%
運算符計算以下等式并返回 余數
作為輸出:
a
= (b
x 某個乘數
) + 余數
其中 某個乘數
是 b
在 a
中能容納的最大倍數。
將 9
和 4
代入此等式,得:
9
= (4
x 2
) + 1
當計算 a
為負值時,采用相同的方法:
-9 % 4 // 等于 -1
將 -9
和 4
代入等式,得:
-9
= (4
x -2
) + -1
因此余數值為 -1
。
對于 b 為負值的情況,其符號將被忽略。這意味著 a % b
和 a % -b
總是給出相同的答案。
3.2、一元負號運算符(-a)
數值的正負號可以使用前綴 -
切換,稱為一元負號運算符:
let three = 3
let minusThree = -three // minusThree 等于 -3
let plusThree = -minusThree // plusThree 等于 3,或 "負負三"
一元負號運算符(-
)直接加在它所作用的值前面,中間沒有任何空格。
3.3、一元正號運算符(+a)
一元正號運算符(+
)只是返回它所作用的值,不做任何改變:
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix 等于 -6
雖然一元加運算符實際上什么也沒做,但是當你使用一元減運算符表示負數時,你可以使用它來使你的代碼對正數也保持對稱性。
4、復合賦值運算符(+=)
與 C 語言一樣,Swift 提供了復合賦值運算符,它將賦值(=
)與另一個操作結合起來。 一個例子是加法賦值運算符(+=
):
var a = 1
a += 2
// a 現在等于 3
表達式 a += 2
是 a = a + 2
的簡寫。 實際上,加法和賦值被合并成一個同時執行這兩個任務的運算符。
注意: 復合賦值運算符不會返回值。 例如,你不能寫 let b = a += 2
。
5、比較運算符(==、!=、>、<、>=、<=)
Swift 支持以下比較運算符:
- 等于(
a == b
) - 不等于(
a != b
) - 大于(
a > b
) - 小于(
a < b
) - 大于等于(
a >= b
) - 小于等于(
a <= b
)
注意: Swift 還提供了兩個標識運算符(===
和 !==
), 你可以用它們來測試兩個對象引用是否指向同一個對象實例。
每個比較運算符都返回一個 Bool
值來指示語句是否為真:
1 == 1 // true 因為 1 等于 1
2 != 1 // true 因為 2 不等于 1
2 > 1 // true 因為 2 大于 1
1 < 2 // true 因為 1 小于 2
1 >= 1 // true 因為 1 大于等于 1
2 <= 1 // false 因為 2 不小于等于 1
比較運算符通常用于條件語句中,例如 if
語句:
let name = "world"
if name == "world" {print("hello, world")
} else {print("I'm sorry \(name), but I don't recognize you")
} // 打印 "hello, world", 因為 name 確實等于 "world"。
如果兩個元組具有相同的類型和相同數量的值,則可以比較它們。 元組是從左到右逐個值進行比較的,直到比較發現兩個不相等的值為止。 這兩個值將進行比較,并且該比較的結果決定了整個元組比較的結果。 如果所有元素都相等,那么這兩個元組本身就相等。 例如:
(1, "zebra") < (2, "apple") // 為 true,因為 1 小于 2; "zebra" 和 "apple" 未比較
(3, "apple") < (3, "bird") // 為 true,因為 3 等于 3,而 "apple" 小于 "bird"
(4, "dog") == (4, "dog") // 為 true,因為 4 等于 4,而 "dog" 等于 "dog"
在上面的示例中,您可以看到第一行的從左到右比較行為。 因為 1
小于 2
,所以 (1, "zebra")
被認為小于 (2, "apple")
,而不管元組中的任何其他值如何。 即使 "zebra"
不小于 "apple"
,也無關緊要,因為比較已經由元組的第一個元素決定了。 但是,當元組的第一個元素相同時,它們的第二個元素_會_進行比較 —— 這就是第二行和第三行發生的情況。
只有當給定的運算符可以應用于各自元組中的每個值時,元組才能與該運算符進行比較。例如,如下面的代碼所示,您可以比較兩個類型為 (String, Int)
的元組,因為 String
和 Int
值都可以使用 <
運算符進行比較。相反,類型為 (String, Bool)
的兩個元組不能使用 <
運算符進行比較,因為 <
運算符不能應用于 Bool
值。
("blue", -1) < ("purple", 1) // 可以,計算結果為 true
("blue", false) < ("purple", true) // 錯誤,因為 < 不能比較布爾值
注意: Swift 標準庫包含用于具有少于七個元素的元組的比較運算符。 要比較具有七個或更多元素的元組, 您必須自己實現比較運算符。
6、三元條件運算符(a>b ? c : d)
三元條件運算符是一種特殊的運算符,用于根據給定條件選擇兩個值中的一個。它由三個部分組成,語法格式為問題 ? 答案1 : 答案2
。它根據問題的真假值來選擇計算哪個表達式,并返回該表達式的值。如果問題
為真,它會計算答案1
并返回其值;否則,它會計算答案2
并返回其值。
三元條件運算符是以下代碼的簡寫形式:
if question {answer1
} else {answer2
}
下面是一個例子,用于計算表格行的高度。如果該行有標題,則行高應比內容高度高 50 點;如果該行沒有標題,則行高應比內容高度高 20 點:
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight 等于 90
上面的例子是下面代碼的簡寫形式:
let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {rowHeight = contentHeight + 50
} else {rowHeight = contentHeight + 20
}
// rowHeight 等于 90
第一個例子使用三元條件運算符意味著rowHeight
可以在一行代碼中設置為正確的值,這比第二個例子中使用的代碼更加簡潔。
三元條件運算符提供了一種有效的簡寫方式來決定考慮兩個表達式中的哪一個。不過,要謹慎使用三元條件運算符。如果過度使用,代碼的可讀性會下降。避免將多個三元條件運算符實例組合成一個復合語句。
7、空合并運算符(a ?? b)
空合并運算符(a ?? b
)如果可選項a
包含一個值,則會解包該值,否則會返回默認值b
(如果a
為nil
)。表達式a
始終是一個可選類型。表達式b
必須與存儲在a
中的類型相匹配。
空合并運算符是以下代碼的簡寫形式:
a != nil ? a! : b
上面的代碼使用三元條件運算符和強制解包(a!
)來訪問 a
中包裝的值(當 a
不是 nil
時),否則返回 b
。空合并運算符提供了一種更優雅的方式,以簡潔和可讀的形式封裝這種條件檢查和解包。
注意: 如果 a
的值是非 nil
的,則不會計算 b
的值。這被稱為短路求值。
下面的示例使用空合并運算符在默認顏色名稱和可選用戶定義的顏色名稱之間進行選擇:
let defaultColorName = "red"
var userDefinedColorName: String? // 默認為 nilvar colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 為空,所以 colorNameToUse 為默認值 "red"
變量 userDefinedColorName
被定義為一個可選的 String
類型,默認值為 nil
。由于 userDefinedColorName
是一個可選類型,你可以使用空合并運算符來考慮它的值。在上面的例子中,該運算符被用于確定一個名為 colorNameToUse
的 String
變量的初始值。因為 userDefinedColorName
是 nil
,所以表達式 userDefinedColorName ?? defaultColorName
返回 defaultColorName
的值,即 "red"
。
如果你給 userDefinedColorName
賦予一個非 nil
的值,并再次執行 nil 合并運算符檢查,那么 userDefinedColorName
包裹的值將被使用,而不是默認值:
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 不是 nil,所以 colorNameToUse 被設置為 "green"
8、區間運算符
Swift 包含幾個區間運算符,這些是表達一個值范圍的快捷方式。
8.1、閉區間運算符(a…b)
閉區間運算符(a...b
)定義了一個從 a
到 b
的范圍,包括 a
和 b
的值。a
的值不能大于 b
。
閉區間運算符在需要使用所有值的情況下很有用,例如在 for-in
循環中:
for index in 1...5 {print("\(index) 乘以 5 等于 \(index * 5)")
}
// 1 乘以 5 等于 5
// 2 乘以 5 等于 10
// 3 乘以 5 等于 15
// 4 乘以 5 等于 20
// 5 乘以 5 等于 25
8.2、半開區間運算符(a…<b)
半開區間運算符(a..<b
)定義了一個從 a
到 b
但不包括 b
的范圍。它被稱為_半開_是因為它包含第一個值但不包含最后一個值。與閉區間運算符一樣,a
的值不能大于 b
。如果 a
等于 b
,那么結果范圍將是空的。
半開區間對于處理從基數 0 開始的列表(如數組)時特別有用,因為它可以計數到列表長度(但不包括列表長度):
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {print("第 \(i + 1) 個人叫 \(names[i])")
}
// 第 1 個人叫 Anna
// 第 2 個人叫 Alex
// 第 3 個人叫 Brian
// 第 4 個人叫 Jack
注意數組包含四個元素,但 0..<count
只計數到 3
(數組中最后一個元素的索引),因為它是一個半開區間。
8.3、單側區間(names[2…])
閉區間運算符有一種替代形式,用于一直延伸到盡可能遠的區間 —— 例如,一個包含從索引 2 到數組末尾所有元素的區間。 在這些情況下,你可以省略區間運算符的一側值。 這種區間被稱為單側區間,因為運算符只有一側有值。 例如:
for name in names[2...] { print(name) }
// Brian
// Jackfor name in names[...2] { print(name) }
// Anna
// Alex
// Brian
半開區間運算符也有一種只寫最后一個值的單側形式。 就像在兩側都包含值時一樣,最后一個值不包含在區間內。 例如:
for name in names[..<2] { print(name) }
// Anna
// Alex
單側區間不僅可以用于下標,還可以用于其他上下文。 對于省略了第一個值的單側區間,你不能遍歷它,因為不清楚他從哪里開始迭代。 你可以遍歷省略了最后一個值的單側區間;但是,由于該區間無限延伸,請確保為循環添加一個顯式的結束條件。 你還可以檢查單側區間是否包含特定值,如下面的代碼所示。
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
8、邏輯運算符(&&、||、!)
邏輯運算符:修改或組合布爾邏輯值 true
和 false
。 Swift 支持 C 語言中的三個標準邏輯運算符:
- 邏輯非(
!a
) - 邏輯與(
a && b
) - 邏輯或(
a || b
)
8.1、邏輯非運算符(!)
邏輯非運算符(!a
)反轉布爾值,使 true
變為 false
,false
變為 true
。
邏輯非運算符是一個前置運算符,緊跟在它所操作的值之前,中間沒有空格。 它可以讀作"非 a
",如下例所示:
讓我們來看一個簡單的例子:
let allowedEntry = false
if !allowedEntry {print("ACCESS DENIED")
} // 打印 "ACCESS DENIED"
短語 if !allowedEntry
可以理解為 “如果不允許進入”。只有當 “不允許進入” 為真時,才會執行后續的那一行;也就是說,如果 allowedEntry
為 false
。
正如這個例子所示,謹慎選擇布爾常量和變量名可以幫助保持代碼的可讀性和簡潔性,同時避免雙重否定或令人困惑的邏輯語句。
8.2、邏輯與運算符(&&)
邏輯與運算符(a && b
) 創建邏輯表達式,其中兩個值都必須為 true
,整個表達式才為 true
。如果任一值為 false
,整個表達式也將為 false
。事實上,如果_第一個_值為 false
,第二個值甚至不會被評估,因為它無論如何都不可能使整個表達式等于 true
。這被稱為_短路求值_。
下面的例子考慮了兩個 Bool
值,只有在兩個值都為 true
時才允許訪問:
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "ACCESS DENIED"
8.3、邏輯或運算符(||)
邏輯或運算符(a || b
) 是由兩個相鄰的管道字符組成的中置運算符。你可以使用它來創建邏輯表達式,在這種表達式中,只要_其中一個_值為 true
,整個表達式就為 true
。
與上面的邏輯與運算符一樣,邏輯或運算符也使用短路求值來考慮它的表達式。如果邏輯或表達式的左側為 true
,右側就不會被評估,因為它無法改變整個表達式的結果。
在下面的例子中,第一個 Bool
值(hasDoorKey
) 為 false
,但第二個值(knowsOverridePassword
) 為 true
。由于有一個值為 true
,整個表達式也將評估為 true
,因此允許訪問:
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"
8.4、組合邏輯運算符
你可以組合多個邏輯運算符來創建更長的復合表達式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"
這個例子使用多個 &&
和 ||
運算符來創建一個更長的復合表達式。然而,&&
和 ||
運算符仍然只作用于兩個值,所以這實際上是三個較小的表達式鏈接在一起。這個例子可以理解為:
如果我們輸入了正確的門禁代碼并通過了視網膜掃描,或者我們有一把有效的門鑰匙,或者我們知道緊急情況下的覆蓋密碼,那么就允許訪問。
根據 enteredDoorCode
、passedRetinaScan
和 hasDoorKey
的值,前兩個子表達式為 false
。然而,由于知道緊急覆蓋密碼,整個復合表達式仍然評估為 true
。
注意: Swift 邏輯運算符 &&
和 ||
遵循從左到右的結合順序,這意味著帶有多個邏輯運算符的復合表達式會首先評估最左邊的子表達式。
8.5、顯式括號
有時即使不嚴格需要,也有必要使用括號來提高復雜表達式的可讀性,讓表達式的意圖更加清晰。 在上面的門禁示例中,為復合表達式的第一部分添加括號是有用的,可以明確表達其意圖:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {print("Welcome!")
} else {print("ACCESS DENIED")
} // 打印 "Welcome!"
括號明確表示前兩個條件被視為整體邏輯中的一種可能狀態。 雖然復合表達式的輸出沒有改變,但整體意圖對讀者來說更加清晰明了。 可讀性永遠比簡潔性更重要,因此在有助于闡明意圖的地方使用括號是很有必要的。