基本操作員
一個運營商是一個特殊的符號,或者你使用來檢查,更改或合并值的短語。例如,加法運算符(+)添加兩個數(shù)字,如in let i = 1 + 2,邏輯AND運算符(&&)組合兩個布爾值,如in if enteredDoorCode && passedRetinaScan。
Swift支持大多數(shù)標準C運算符,并改進了幾種消除常見編碼錯誤的功能。賦值運算符(=)不會返回值,以防止在等于運算符(==)時錯誤地使用該值。算術(shù)運算符(+,-,*,/,%等等)檢測和禁止值溢出,與變得比存儲它們的類型的所允許的值的范圍更大或更小數(shù)目的工作時避免意外的結(jié)果。您可以通過使用雨燕的溢出運營商選擇在價值溢出行為,如在溢出運營商。
Swift還提供了在C中沒有的范圍運算符,比如a..<b和a...b,作為表達一系列值的快捷方式。
本章介紹Swift中的常用操作符。高級操作符涵蓋了Swift的高級操作符,并描述了如何定義自己的自定義操作符并為您自定義的類型實現(xiàn)標準操作符。
術(shù)語
運算符是一元,二元或三元運算符:
一元運算符在單個目標上運行(例如
-a)。一元前綴運算符緊挨著它們的目標(例如!b)出現(xiàn),而一元后綴運算符出現(xiàn)在它們的目標之后(例如c!)。二元操作符運行在兩個目標上(如
2 + 3),并且是中綴,因為它們出現(xiàn)在兩個目標之間。三元運營商在三個目標上運營。像C一樣,Swift只有一個三元運算符,即三元條件運算符(
a ? b : c)。
操作符影響的值是操作數(shù)。在表達式中1 + 2,+符號是二元運算符,它的兩個操作數(shù)是值1和2。
賦值運算操作
該賦值運算符(a = b)初始化或更新的價值a與價值b:
let b = 10var a = 5a = b// a is now equal to 10
如果賦值的右側(cè)是一個具有多個值的元組,則其元素可以一次分解為多個常量或變量:
let (x, y) = (1, 2)// x is equal to 1, and y is equal to 2print(x) //1
與C和Objective-C中的賦值運算符不同,Swift中的賦值運算符本身不返回值。以下聲明無效:
if x = y {// This is not valid, because x = y does not return a value.}
此功能可以防止賦值運算=符(==)在實際意圖等于運算符()時被意外使用。通過使if x = y無效,Swift可以幫助您避免代碼中出現(xiàn)這些類型的錯誤。
算術(shù)運算符
Swift支持所有數(shù)字類型的四個標準算術(shù)運算符:
加法(
+)減法(
-)乘法(
*)司(
/)
1 + 2 // equals 35 - 3 // equals 22 * 3 // equals 610.0 / 2.5 // equals 4.0
與C和Objective-C中的算術(shù)運算符不同,Swift算術(shù)運算符默認情況下不允許值溢出。你可以通過使用Swift的溢出操作符(比如a &+ b)來選擇賦值溢出行為。請參閱溢出操作符。
String連接 操作還支持連接:
"hello, " + "world" // equals "hello, world"
剩余操作員
該余運算符(a % b)的作品如何的好幾倍b將適合的內(nèi)部a,并返回剩下值(被稱為剩余部分)。
注意
余數(shù)運算符(%)在其他語言中也稱為模運算符。然而,它在Swift中對負數(shù)的行為意味著嚴格地說,它是一個余數(shù)而不是模操作。
以下是剩余操作符的工作方式。為了計算9 % 4,你首先要計算出有多少個4s可以放入里面9:
<figure class="figure" style="font-size: 0.8rem;">[圖片上傳失敗...(image-3b7ddc-1531103258569)]
</figure>
你可以放入兩個4s 9,剩下的就是1(以橙色顯示)。
在Swift中,這會寫成:
9 % 4 // equals 1
為了確定答案a % b,%操作員計算下面的公式并remainder作為其輸出返回:
a=(bx some multiplier)+remainder
里面some multiplier最大的倍數(shù)是 哪里? b``a
插入9和4這個公式得到:
9=(4x 2)+1
計算余數(shù)為負值時應(yīng)用同樣的方法a:
-9 % 4 // equals -1
插入-9和4代入公式得到:
-9=(4x -2)+-1
給出一個余數(shù)值-1。
b負號的值將忽略 符號b。這意味著a % b并a % -b始終給出相同的答案。
一元減法運算符
數(shù)值的符號可以使用前綴-(稱為一元減運算符)來切換:
let three = 3let minusThree = -three // minusThree equals -3let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元減號運算符(-)直接位于運算值的前面,沒有任何空格。
一元加運算符
在一元加運算(+)只返回其所操作的價值,沒有任何變化:
let minusSix = -6let alsoMinusSix = +minusSix // alsoMinusSix equals -6
雖然一元加運算符實際上并沒有做任何事情,但是在使用一元減運算符來表示負數(shù)時,也可以使用它來在代碼中提供正數(shù)的對稱性。
復(fù)合分配算子
和C一樣,Swift提供了復(fù)合賦值操作符,它將assignment(=)與另一個操作結(jié)合在一起。一個例子是附加賦值運算符(+=):
var a = 1a += 2// a is now equal to 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)更多信息,請參閱類和結(jié)構(gòu)。
每個比較運算符都會返回一個Bool值來指示該語句是否為真:
1 == 1 // true because 1 is equal to 12 != 1 // true because 2 is not equal to 12 > 1 // true because 2 is greater than 11 < 2 // true because 1 is less than 21 >= 1 // true because 1 is greater than or equal to 12 <= 1 // false because 2 is not less than or equal to 1
比較運算符通常用于條件語句中,如if語句:
let name = "world"if name == "world" {print("hello, world")} else {print("I'm sorry \(name), but I don't recognize you")}// Prints "hello, world", because name is indeed equal to "world".
有關(guān)該if聲明的更多信息,請參閱控制流程。
你可以比較兩個元組,如果它們具有相同的類型和相同數(shù)量的值。元組從左到右進行比較,一次一個值,直到比較發(fā)現(xiàn)兩個不相等的值。這兩個值進行比較,比較的結(jié)果決定了元組比較的總體結(jié)果。如果所有元素都相等,那么元組本身是相等的。例如:
(1, "zebra") < (2, "apple") // true because 1 is less than 2; "zebra" and "apple" are not compared(3, "apple") < (3, "bird") // true because 3 is equal to 3, and "apple" is less than "bird"(4, "dog") == (4, "dog") // true because 4 is equal to 4, and "dog" is equal to "dog"
在上面的示例中,您可以在第一行看到從左到右的比較行為。因為1小于2,(1, "zebra")被認為小于(2, "apple"),不管元組中的任何其他值如何。沒關(guān)系,"zebra"不小于"apple",因為比較已經(jīng)由元組的第一個元素決定了。然而,當元組的第一個元素是相同的,他們的第二個元素進行比較 - 這是發(fā)生在第二和第三行。
只有當操作符可以應(yīng)用于各個元組中的每個值時,元組才可以與給定的操作符進行比較。例如,這表現(xiàn)在下面的代碼,就可以比較類型的兩個元組(String, Int),因為這兩個String和Int值可以使用進行比較<運算符。相比之下,兩個元組類型(String, Bool)不能與<運算符進行比較,因為<運算符不能應(yīng)用于Bool值。
("blue", -1) < ("purple", 1) // OK, evaluates to true("blue", false) < ("purple", true) // Error because < can't compare Boolean values
注意
Swift標準庫包含元組少于7個元組的元組比較運算符。要比較具有七個或更多元素的元組,您必須自己實現(xiàn)比較運算符。
三元條件運算符
所述三元條件算子是由三個部分組成,這需要形式的特殊操作question ? answer1 : answer2。這是根據(jù)是否question為真來評估兩個表達式之一的捷徑。如果question屬實,則評估answer1并返回其值; 否則,它會評估answer2并返回其值。
三元條件運算符是下面代碼的簡寫:
if question {answer1} else {answer2}
以下是一個計算表格行高度的示例。如果該行有標題,則行高應(yīng)比內(nèi)容高度高50個點;如果該行沒有標題,則行高應(yīng)高20個點:
let contentHeight = 40let hasHeader = truelet rowHeight = contentHeight + (hasHeader ? 50 : 20)// rowHeight is equal to 90
上面的例子是下面代碼的簡寫:
let contentHeight = 40let hasHeader = truelet rowHeight: Intif hasHeader {rowHeight = contentHeight + 50} else {rowHeight = contentHeight + 20}// rowHeight is equal to 90
第一個例子使用三元條件運算符意味著rowHeight可以在單行代碼上設(shè)置正確的值,這比第二個例子中使用的代碼更簡潔。
三元條件運算符為決定要考慮哪兩個表達式提供了有效的速記。但是,請謹慎使用三元條件運算符。如果過度使用,它的簡潔會導(dǎo)致難以閱讀的代碼。避免將三元條件運算符的多個實例組合成一個復(fù)合語句。
無合并操作員
的零-合并運算符(a ?? b)進行解包的可選a,如果它包含一個值,或者返回一個默認值b,如果a是nil。表達式a總是可選的類型。表達式b必須與存儲在里面的類型匹配a。
nil-coalescing運算符是下面代碼的簡寫:
a != nil ? a! : b
上面的代碼使用三元條件操作和強制解包(a!)來訪問內(nèi)部包裹的值a時a是不nil,并返回b,否則。nil-coalescing運算符提供了一種更簡潔的方式來以簡明易懂的形式封裝這個條件檢查和解包。
注意
如果值為a非nil值,b則不評估值。這就是所謂的短路評估。
下面的示例使用nil-coalescing運算符在默認顏色名稱和可選的用戶定義顏色名稱之間進行選擇:
let defaultColorName = "red"var userDefinedColorName: String? // defaults to nilvar colorNameToUse = userDefinedColorName ?? defaultColorName// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
該userDefinedColorName變量被定義為可選的String,默認值為nil。由于userDefinedColorName是可選類型,因此您可以使用nil-coalescing運算符來考慮其值。在上面的示例中,運算符用于確定String調(diào)用變量的初始值colorNameToUse。因為userDefinedColorName是nil,表達式userDefinedColorName ?? defaultColorName返回值defaultColorName或"red"。
如果您將一個非nil值賦予userDefinedColorName并再次執(zhí)行nil-coalescing操作符檢查,則將userDefinedColorName使用內(nèi)部包裝的值而不是缺省值:
userDefinedColorName = "green"colorNameToUse = userDefinedColorName ?? defaultColorName// userDefinedColorName is not nil, so colorNameToUse is set to "green"
范圍運算符
Swift包含幾個范圍運算符,它們是表示一系列值的捷徑。
關(guān)閉范圍操作員
的封閉范圍操作符(a...b)限定了從運行范圍a來b,并且包括這些值a和b。值a不得大于b。
在遍歷希望使用所有值的范圍(例如使用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ū)間運算符(a..<b)限定了從運行范圍a到b,但不包括b。據(jù)說它是半開放的,因為它包含了它的第一個值,但不包含它的最終值。與封閉范圍操作符一樣,值a不得大于b。如果值a等于b,則結(jié)果范圍將為空。
當您使用基于零的列表(例如數(shù)組)時,半開范圍特別有用,可以計算(但不包括)列表長度:
let names = ["Anna", "Alex", "Brian", "Jack"]let count = names.countfor 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ù)組。
單面范圍
閉范圍運算符有一種替代形式,用于在一個方向上盡可能延續(xù)的范圍 - 例如,范圍包括從索引2到數(shù)組末尾的所有數(shù)組元素。在這些情況下,可以省略范圍運算符一側(cè)的值。這種范圍被稱為單邊范圍,因為操作員只有一方的價值。例如:
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
片面范圍可以用在其他情況下,而不僅僅用于下標。您不能迭代忽略第一個值的單側(cè)范圍,因為尚不清楚應(yīng)在哪里開始迭代。您可以遍歷一個忽略其最終值的單側(cè)范圍; 但是,由于范圍無限期地繼續(xù),因此請確保為循環(huán)添加明確的結(jié)束條件。您還可以檢查單側(cè)范圍是否包含特定值,如下面的代碼所示。
let range = ...5range.contains(7) // falserange.contains(4) // truerange.contains(-1) // true
邏輯運算符
邏輯運算符修改或組合布爾邏輯值true和false。Swift支持基于C語言中的三種標準邏輯運算符:
邏輯NOT(
!a)邏輯與(
a && b)邏輯或(
a || b)
邏輯NOT運算符
的邏輯非運算符(!a)反轉(zhuǎn)一個布爾值,使得true成為false,和false變true。
邏輯NOT運算符是前綴運算符,并且在其運行的值之前立即出現(xiàn),沒有任何空格。它可以被解讀為“不a”,如下例所示:
let allowedEntry = falseif !allowedEntry {print("ACCESS DENIED")}// Prints "ACCESS DENIED"
該短語if !allowedEntry可以被理解為“如果不允許進入”。后續(xù)行僅在“不允許進入”為真時才被執(zhí)行; 那就是,如果allowedEntry是false。
正如在這個例子中,仔細選擇布爾常量和變量名稱可以幫助保持代碼的可讀性和簡潔性,同時避免雙重否定或混淆邏輯語句。
邏輯AND運算符
的邏輯AND運算符(a && b)創(chuàng)建邏輯表達式,其中這兩個值必須true為整體表達也有true。
如果任何一個值都是false,則整體表達式也將是false。事實上,如果第一個值是false第二個值,那么甚至不會評估第二個值,因為它不可能使整體表達式等于true。這就是所謂的短路評估。
這個例子考慮兩個Bool值,并且只允許訪問如果價值觀true:
let enteredDoorCode = truelet passedRetinaScan = falseif enteredDoorCode && passedRetinaScan {print("Welcome!")} else {print("ACCESS DENIED")}// Prints "ACCESS DENIED"
邏輯OR運算符
的邏輯OR運算符(a || b)是來自兩個相鄰管字符制成中綴運算符。您可以使用它來創(chuàng)建邏輯表達式,其中只有一個值必須true用于整體表達式true。
像上面的邏輯與運算符一樣,邏輯或運算符使用短路評估來考慮其表達式。如果邏輯或表達式的左側(cè)是true,右側(cè)不計算,因為它不能改變整個表達式的結(jié)果。
在下面的例子中,第一個Bool值(hasDoorKey)是false,但第二個值(knowsOverridePassword)是true。因為有一個值true,整體表達式也可以評估true,并且允許訪問:
let hasDoorKey = falselet knowsOverridePassword = trueif hasDoorKey || knowsOverridePassword {print("Welcome!")} else {print("ACCESS DENIED")}// Prints "Welcome!"
邏輯運算符的組合
您可以組合多個邏輯運算符來創(chuàng)建更長的復(fù)合表達式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {print("Welcome!")} else {print("ACCESS DENIED")}// Prints "Welcome!"
此示例使用多個&&和||運算符來創(chuàng)建較長的復(fù)合表達式。然而,&&和||運算符仍然只能運行兩個值,所以這實際上是三個較小的表達式鏈接在一起。該示例可以解讀為:
如果我們輸入了正確的門碼并通過了視網(wǎng)膜掃描,或者如果我們有一個有效的門鑰匙,或者我們知道緊急改寫密碼,則允許進入。
基于,和的值enteredDoorCode,前兩個子表達式是。但是,緊急重寫密碼是已知的,因此整體復(fù)合表達式仍然會評估為。 passedRetinaScan``hasDoorKey``false``true
注意
迅捷邏輯運算符&&和||是左結(jié)合,這意味著與多個邏輯運算符復(fù)合表達式首先評估最左邊的子表達式。
顯式括號
在不嚴格需要的情況下包含括號有時很有用,可以使復(fù)雜表達式的意圖更容易閱讀。在上面的門訪問示例中,在復(fù)合表達式的第一部分周圍添加圓括號以使其意圖明確是有用的:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {print("Welcome!")} else {print("ACCESS DENIED")}// Prints "Welcome!"
括號清楚地表明前兩個值在總體邏輯中被認為是單獨的可能狀態(tài)的一部分。復(fù)合表達式的輸出不變,但整體意圖對讀者更清楚??勺x性始終優(yōu)于簡潔性; 在他們幫助明確你的意圖的地方使用括號。