案例代碼下載
基本運算符
一個運算符是一個特殊的符號,或者你使用來檢查,更改或合并值的短語。例如,加法運算符(+)對兩個數(shù)字相加,如:let i = 1 + 2,和AND邏輯運算符(&&)組合兩個布爾值,如:&if enteredDoorCode && passedRetinaScan
Swift支持大多數(shù)標準C運算符,并改進了幾種消除常見編碼錯誤的功能。賦值運算符(=)不返回值,以防止在相等運算(==)意圖時錯誤地使用它。算術(shù)運算符(+,-,*,/,%等等)檢測和禁止值溢出,來避當工作時數(shù)據(jù)比存儲它們的類型所允許范圍更大或更小而發(fā)生免意外的結(jié)果。在面對數(shù)值溢出行為可以選擇使用溢出運算符,在溢出運算符中描述。
Swift還提供了在C中不存在的區(qū)間運算符,例如a..<b和a...b表示一系列值范圍的快捷方式。
本章介紹Swift中的常用運算符。高級運算符涵蓋了Swift的高級運算符,并描述了如何定義自定義運算符并為自定義類型實現(xiàn)標準運算符。
術(shù)語
運算符是一元的,二元的或三元的:
- 一元運算符作用于單個目標上(例如-a)。一元前綴運算符出現(xiàn)在它們的目標之前(例如!b),而一元后綴運算符緊跟在它們的目標之后(例如c!)。
- 二元運算符作用于兩個目標(例如2 + 3),并且是中綴,因為它們出現(xiàn)在兩個目標之間。
- 三元運算符在三個目標上操作。與C一樣,Swift只有一個三元運算符,即三元條件運算符(a ? b : c)。
運算符影響的值是操作數(shù)。在表達式1 + 2中,符號+是二元運算符,它的兩個操作數(shù)是值1和2。
賦值運算符
該賦值運算符(a = b)用b的值初始化或更新a的值
let b = 10
var a = 5
a = b//a的值為10
如果賦值的右側(cè)是具有多個值的元組,則其元素可以一次分解為多個常量或變量:
let (x, y) = (1, 2)
與C和Objective-C中的賦值運算符不同,Swift中的賦值運算符本身不返回值。以下聲明無效:
if let x = y {
//這是無效的,因為x = y不返回值
}
此功能可防止在實際使用等于運算符(==)時意外使用賦值運算符(=)。通過使if x = y無效,Swift可以幫助您避免代碼中的這類錯誤。
算術(shù)運算符
Swift支持所有數(shù)字類型的四個標準算術(shù)運算符:
- 加法(+)
- 減法(-)
- 乘法(*)
- 除法(/)
1 + 2
5 - 3
2*3
10.0/2.5
與C和Objective-C中的算術(shù)運算符不同,Swift算術(shù)運算符默認情況下不允許值溢出。您可以通過使用Swift的溢出運算符來選擇值溢出行為(例如 a &+ b)。請參閱溢出運算符。
加法運算符也支持String連接:
"hello, " + "world"http://等于"hello, world"
取余運算符
取余運算符(a % b)a的多少倍適合b,并返回剩下值(被稱為剩余部分)。
注意:取余運算符(%)在其他語言也稱為模運算符。然而,它在Swift中對負數(shù)的行為意味著,嚴格來說,它是一個余數(shù)而不是模運算。
以下是取余運算符的工作原理。要計算9 % 4,你首先計算出4的多少倍適合9:

你可以在9里面放兩個4,其余的是1(用橙色表示)。
在Swift中,這將寫成:
9%4//等于1
為確定a % b的答案,%運算符計算以下等式并將remainder作為其輸出返回
a = (b x some multiplier) + remainder
some multiplierba是最適合的內(nèi)部倍數(shù)。
插入9和4輸入此等式可得出:
9=(4x 2)+1
在計算負值a的余數(shù)時應(yīng)用相同的方法:
-9%4//等于-1
插入-9和4輸入等式產(chǎn)生:
-9=(4x -2)+-1
給出余數(shù)值-1。
對于負值b,忽略符號b。這意味著a % b和a % -b的結(jié)果相同。
一元減運算符
可以使用前綴-(稱為一元減運算符)來切換數(shù)值的符號:
let three = 3
let minusThree = -three//-3
let plusThree = -minusThree//3
一元減運算符(-)直接位于它作用的值之前,沒有任何空格。
一元加運算符
一元加運算符(+)只返回其所作用的值,沒有任何變化:
let minusSix = -6
let alsoMinusSix = +minusSix//6
雖然一元加運算符實際上沒有做任何事情,但是當使用一元減運算符作為負數(shù)時,您可以使用它來為代碼提供正數(shù)的對稱性。
復(fù)合賦值運算符
與C一樣,Swift提供了將賦值運算符(=)與另一個操作相結(jié)合的復(fù)合賦值運算符。一個例子是加法賦值運算符(+=):
var a = 1
a += 2//3
表達式a += 2是a = a + 2的簡寫。實際上,相加和賦值組合成一個同時執(zhí)行兩個任務(wù)的運算符。
注意: 復(fù)合賦值運算符不返回值。例如,你不能寫let b = a += 2。
有關(guān)Swift標準庫提供的運算符的信息,請參閱運算符聲明。
比較運算符
Swift支持所有標準C 比較運算符:
- 等于(a == b)
- 不等于(a != b)
- 大于(a > b)
- 小于(a < b)
- 大于或等于(a >= b)
- 小于或等于(a <= b)
注意: Swift還提供了兩個恒等運算符( === 和 !== ),用于測試兩個對象引用是否都引用同一個對象實例。有關(guān)更多信息,請參閱Identity Operators。
每個比較運算符都返回一個Bool值,以該語句是否為true:
1 == 1//true
2 != 1//true
2 > 1//true
1 < 2//true
1 >= 1//true
2 <= 1//false
比較運算符通常用于條件語句,例如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".
有關(guān)該if語句的更多信息,請參閱控制流。
如果它們具有相同的類型和相同的值,則可以比較兩個元組。元組從左到右進行比較,一次一個值,直到比較找到兩個不相等的值。比較這兩個值,并且該比較的結(jié)果確定元組比較的總體結(jié)果。如果所有元素都相等,則元組本身是相等的。例如:
(1, "zebra") < (2, "apple") // true 因為 1 is 小于 2; "zebra" and "apple" 不會被比較
(3, "apple") < (3, "bird") // true 因為 3 is 等于 3, and "apple" 小于 "bird"
(4, "dog") == (4, "dog") // true 因為 4 is 等于 4, and "dog" 等于 "dog"
在上面的示例中,您可以在第一行看到從左到右的比較行為。因為1小于2,(1, "zebra")被認為小于(2, "apple"),不管元組中的任何其他值。"zebra"不小于"apple"這不要緊,,因為比較已經(jīng)由元組的第一個元素決定。但是,當元組的第一個元素相同時,它們的第二個元素會被比較 - 這就是第二行和第三行發(fā)生的情況。
僅當運算符可以應(yīng)用于相應(yīng)元組中的每個值時,才能將元組與給定運算符進行比較。例如,下面的代碼所示,您可以比較(String, Int)兩個類型的元組,因為可以使用<運算符比較String和Int兩者的值。相反,兩個(String, Bool)類型的元組無法與<運算符進行比較,因為<運算符不能應(yīng)用于Bool值。
("blue", -1) < ("purple", 1) // 正確, 結(jié)果:true
("blue", false) < ("purple", true) // 錯誤 因為 < 不能比較 Boolean 值
注意: Swift標準庫包含的元組比較運算符,元組必須少于7個元素。要將七個或更多元素的元組進行比較,您必須自己實現(xiàn)比較運算符。
三元條件運算符
所述三元條件運算符是由question ? answer1 : answer2形式的三個部分組成的特殊操作。它是根據(jù)question是真還是假來評估兩個表達式之一的快捷方式。如果question為true,則計算并返回answer1的值; 否則,它會評估并返回answer2的值。
三元條件運算符是以下代碼的簡寫:
if question {
answer1
} else {
answer2
}
這是一個例子,它計算表格行的高度。如果行有標題,行高應(yīng)該比內(nèi)容高度高50個點,如果行沒有標題,則行高應(yīng)該高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可以在單行代碼上設(shè)置正確的值,這比第二個示例中使用的代碼更簡潔。
三元條件運算符提供了一種有效的簡寫,用于決定要考慮兩個表達式中的哪一個。但是,請謹慎使用三元條件運算符。如果過度使用,它的簡潔性會導(dǎo)致難以閱讀的代碼。避免將三元條件運算符的多個實例組合到一個復(fù)合語句中。
Nil-Coalescing運算符
Nil-Coalescing運算符(a ?? b)如果可選值a包含一個值則進行解包,如果是nil返回一個默認b值。表達式a始終是可選類型。表達式b必須與存儲在a中的類型匹配。
nil-coalescing運算符是下面代碼的簡寫:
a != nil ? a! : b
上面的代碼使用三元條件運算符和強制解包(a!)當a不是nil時來訪問內(nèi)部包裹的a值,否則返回b。nil-coalescing運算符提供了一種更簡潔的方式來以簡潔易讀的形式封裝此條件檢查和展開。
注意: 如果值為a不是nil,則不評估b的值。這被稱為短路評估。
下面的示例使用nil-coalescing運算符在默認顏色名稱和可選的用戶定義顏色名稱之間進行選擇:
let defaultColorName = "red"
var userDefinedColorName: String? // 默認是 nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 是 nil, 因此 colorNameToUse 被設(shè)置為默認的 "red"
該userDefinedColorName變量被定義為可選的String,具有默認值nil。因為userDefinedColorName是可選類型,您可以使用nil-coalescing運算符來考慮其值。在上面的示例中,運算符用于確定叫做colorNameToUse的String變量的初始值。因為userDefinedColorName是nil,userDefinedColorName ?? defaultColorName表達式返回defaultColorName的值,否則為"red"。
如果為非nil值賦值userDefinedColorName并再次執(zhí)行nil-coalescing運算符檢查,userDefinedColorName則使用包含在內(nèi)的值而不是默認值:
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName 不是 nil, 因此 colorNameToUse 被設(shè)置為 "green"
區(qū)間運算符
Swift包含多個區(qū)間運算符,它們是表示一系列值的快捷方式。
閉區(qū)間運算符
閉區(qū)間運算符(a...b)限定了從運行范圍a到b,并且包括這些值a和b。值a不得大于b。
當在您希望使用所有值的范圍內(nèi)進行迭代時,閉區(qū)間運算符非常有用,例如使用for- in循環(huán):
for index in 1...5 {
print("\(index) times 5 is \(index * 5)")
}
// 1 times 5 is 5
// 2 times 5 is 10
// 3 times 5 is 15
// 4 times 5 is 20
// 5 times 5 is 25
有關(guān)for- in循環(huán)的更多信息,請參閱控制流。
半開區(qū)間運算符
所述半開區(qū)間運算符(a..<b)限定了從運行范圍a到b,但不包括b。它被認為是半開放的,因為它包含它的第一個值,但不包含它的最終值。與閉區(qū)域運算符一樣,值a不得大于b。如果值a等于b,則結(jié)果范圍將為空。
當您使用基于零的列表(如數(shù)組)時,半開范圍特別有用,其中計算列表的長度(但不包括)非常有用:
let names = ["Anna", "Alex", "Brian", "Jack"]
let count = names.count
for i in 0..<count {
print("Person \(i + 1) is called \(names[i])")
}
// Person 1 is called Anna
// Person 2 is called Alex
// Person 3 is called Brian
// Person 4 is called Jack
請注意,該數(shù)組包含四個項目,但0..<count只計算3(數(shù)組中最后一項的索引),因為它是半開放范圍。有關(guān)數(shù)組的更多信息,請參閱數(shù)組。
單向區(qū)間
閉區(qū)域運算符有一個替代形式,用于在一個方向上盡可能繼續(xù)的范圍 - 例如,包括從索引2到數(shù)組末尾的數(shù)組的所有元素的范圍。在這些情況下,您可以省略范圍運算符一側(cè)的值。這種范圍稱為單側(cè)范圍,因為運算符僅在一側(cè)具有值。例如:
for name in names[2...] {
print(name)
}
// Brian
// Jack
for name in names[...2] {
print(name)
}
// Anna
// Alex
// Brian
半開區(qū)間運算符也具有單側(cè)形式,僅使用其最終值編寫。就像在兩側(cè)都包含值一樣,最終值不是范圍的一部分。例如:
for name in names[..<2] {
print(name)
}
// Anna
// Alex
單向區(qū)間可以在其他上下文中使用,而不僅僅在下標中使用。您不能迭代忽略第一個值的單側(cè)范圍,因為不清楚迭代應(yīng)該從何處開始。您可以迭代忽略其最終值的單向區(qū)間; 但是,因為范圍無限期地繼續(xù),請確保為循環(huán)添加顯式結(jié)束條件。您還可以檢查單向區(qū)間是否包含特定值,如下面的代碼所示。
let range = ...5
range.contains(7) // false
range.contains(4) // true
range.contains(-1) // true
邏輯運算符
邏輯運算符修改或組合布爾邏輯值true和false。Swift支持基于C語言的三個標準邏輯運算符:
- 邏輯NOT(!a)
- 邏輯AND()a && b
- 邏輯OR()a || b
邏輯非運算符
的邏輯非運算符(!a)反轉(zhuǎn)一個布爾值,使得true成為false,或者false變true。
邏輯非運算符是前綴運算符,并且在它運行的值之前立即出現(xiàn),沒有任何空格。它可以讀作“not a”,如下例所示:
let allowedEntry = false
if !allowedEntry {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
!allowedEntry短語可以讀作“如果非allowedEntry。”后續(xù)行僅在“非allowedEntry”為真時執(zhí)行; 也就是說allowedEntry為false
在這個例子中,仔細選擇布爾常量和變量名稱有助于保持代碼的可讀性和簡潔性,同時避免雙重否定或混淆邏輯語句。
邏輯AND運算符
邏輯AND運算符(a && b)創(chuàng)建邏輯表達式,其中這兩個值必須為true整體表達式才為true。如果任一值false,則整體表達式將是false。實際上,如果第一個值是false,則第二個值不會被計算,因為它不可能使整個表達式等于true。這被稱為短路評估。
此示例考慮兩個Bool值,并且只有兩個值都為true時允許執(zhí)行:
let enteredDoorCode = true
let passedRetinaScan = false
if enteredDoorCode && passedRetinaScan {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
邏輯OR運算符
邏輯OR運算符(a || b)是來自兩個相鄰|字符制成中綴運算符。您可以使用它來創(chuàng)建邏輯表達式,其中有一個或兩個值為true則整個表達式是true。
與上面的邏輯AND運算符一樣,邏輯OR運算符使用短路評估來考慮其表達式。如果邏輯OR表達式的左側(cè)是true,則不評估右側(cè),因為它不能更改整個表達式的結(jié)果。
在下面的示例中,第一個Bool值(hasDoorKey)是false,但第二個值(knowsOverridePassword)是true。因為有一個值是true,整個表達式也會計算為true,并允許訪問:
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
結(jié)合邏輯運算符
您可以組合多個邏輯運算符來創(chuàng)建更長的復(fù)合表達式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
此示例使用多個 &&和||運算符創(chuàng)建更長的復(fù)合表達式。然而&&和||運算符仍然只運行兩個值,所以這實際上是三個較小的表達式鏈接在一起。該示例可以理解為:
如果我們輸入了正確的門禁密碼并通過了視網(wǎng)膜掃描,或者我們有一個有效的門鑰匙,或者我們知道緊急覆蓋密碼,那么允許訪問。
基于enteredDoorCode、passedRetinaScan和hasDoorKey的值,前兩個子表達式是false。但是,緊急覆蓋密碼是true,因此整個復(fù)合表達式仍然評估為true。
注意: Swift邏輯運算符&&和||是左結(jié)合,這意味著與多個邏輯運算符復(fù)合表達式首先評估最左邊的子表達式。
明確的括號
當它們不是嚴格需要有時包含括括號是有用的,以使復(fù)雜表達的意圖更容易閱讀。在上面的進門的示例中,在復(fù)合表達式的第一部分周圍添加括號以使其意圖明顯是有用的:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
括號清楚地表明前兩個值被視為整體邏輯中單獨可能狀態(tài)的一部分。復(fù)合表達式的輸出不會改變,但讀者的整體意圖更清晰。可讀性始終優(yōu)于簡潔; 使用括號,幫助他們明確你的意圖。