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