運算符 是可以檢查,修改或者組合值的特殊符號或者短語。例如,加法運算符(+
)將兩個數相加,像let i = 1 + 2
,邏輯與運算符組合兩個布爾值,像if enteredDoorCode && passedRetinaScan
。
Swift支持大多數標準C運算符并且改善了一些功能來避免常見的編碼錯誤。賦值運算符(=
)不會返回一個值,避免被錯誤的當成等于運算符(==
)使用。數學運算符(+
,-
,*
,/
,%
等等)會檢測并且不允許值溢出,避免使用一些過大或者過小以致超出存儲它們的類型允許范圍的值而導致意外的結果。可以通過使用Swift的溢出運算符來處理值溢出的情況,詳見溢出運算符。
Swift同樣提供了兩個C沒有的區間運算符(a..<b
和a...b
),作為描述區間值的簡寫。
本章講述Swift的基礎運算符。高級運算符章節會介紹Swift的高級運算符,并會介紹如何定義一個自定義運算符,以及為你的自定義類型實現運算符重載。
目錄
- 術語
- 賦值運算符
- 數學運算符
- 組合賦值運算符
- 比較運算符
- 三元條件運算符
- Nil聚合運算符
- 區間運算符
- 邏輯運算符
術語
運算符可以是一元,二元者三元的:
- 一元運算符作用于一個單獨對象(例如
-a
)。一元前置運算符出現在對象的前面(例如!b
),一元后置運算符出現在對象的后面(例如c!
)。 - 二元運算符作用于兩個對象,是中置的,因為它出現在兩個對象中間。
- 三元運算符作用于三個對象。和C一樣,Swift只有一個三元運算符:三元條件運算符(
a ? b : c
)。
運算符影響的值稱為運算對象。在表達式1 + 2
中,符號+
是一個二元運算符,它的兩個運算對象是值1
和2
。
賦值運算符
賦值運算符(a = b
)初始化或者更新a
的值為b
。
let b = 10
var a = 5
a = b
// a is now equal to 10
如果賦值的右邊是一個包含多個值的元組,它的元素可以一次被分解成不同的常量或者變量:
let (x, y) = (1, 2)
// x is equal to 1, and y is equal to 2
和C與OC的賦值運算符不同,Swift的賦值運算符本身不會返回一個值,以下聲明是非法的:
if x = y {
// This is not valid, because x = y does not return a value.
}
這個特性避免了賦值運算符(=
)錯誤的被用成等于運算符(==
)。通過讓if x = y
非法,Swift幫助你避免了代碼中的這些錯誤。
數學運算符
Swift為所有的數值類型提供了四種標準的數學運算符:
- 加法(
+
) - 減法(
-
) - 乘法(
*
) - 除法(
/
)
1 + 2 // equals 3
5 - 3 // equals 2
2 * 3 // equals 6
10.0 / 2.5 // equals 4.0
和C與OC的數學運算符不同,Swift的數學運算符默認是不允許值溢出的。可以使用Swift的溢出運算符來處理值溢出的情況(例如a &+ b
)。詳見溢出運算符。
加法運算符同樣適用于String
的拼接:
"hello, " + "world" // equals "hello, world"
取余運算符
取余運算符 (a % b
)會計算出b
的多少倍最接近a
,并返回剩余的值(也就是余數)。
注意
取余運算符(%
)在其它語言中被稱作模運算符 。但是在Swift中對于負數的這種操作,嚴格來說是一個取余運算而不是一個模運算。
下面展示了取余運算符是如何工作的。為了計算9 % 4
,首先需要計算出4
的多少倍最接近9
。
你可以算出
4
的兩倍最接近9
,所以余數是1
(圖中橙色所示)。在Swift中,可以寫成:
9 % 4 // equals 1
為了確定a % b
的答案,%
運算符計算以下的等式并返回remainder
作為輸出:
a = (b x some multiplier) + remainder
在這個等式中,some multiplier
是在滿足最接近a
的前提下b
的最大乘數。
將9
和4
帶入等式,結果如下:
9 = (4 x 2) + 1
同樣的方法也是用于當a
是一個負數時:
-9 % 4 // equals -1
將-9
和4
帶入等式,結果如下:
-9 = (4 x -2) + -1
得出余數為-1
。
當b
是負數時符號可忽略,這意味著a % b
和a % -b
的結果總是一樣。
一元負運算符
可以使用前綴-
確定一個數值型值的符號,它被稱為一元負運算符。
let three = 3
let minusThree = -three // minusThree equals -3
let plusThree = -minusThree // plusThree equals 3, or "minus minus three"
一元運算符(-
)直接放在運算對象前,沒有任何空格。
一元正運算符
一元正運算符 (+
)僅僅返回運算對象的值,沒有任何改變:
let minusSix = -6
let alsoMinusSix = +minusSix // alsoMinusSix equals -6
盡管+
實質上什么都沒做,但是當在代碼中使用了-
時,可以用+
提供對稱性。
組合賦值運算符
像C一樣,Swift提供了組合賦值運算符 ,它將=
和其它運算符組合使用。一個組合賦值運算符的例子是加等于運算符 (+=
)。
var a = 1
a += 2
// a is now equal to 3
表達式a += 2
是a = a + 2
的簡寫。效率起見,加法和賦值組合進一個運算符來同時執行兩個操作。
注意
組合賦值運算符并不返回一個值。例如,不能寫成let b = a += 2
。
想了解Swift標準庫提供的組合賦值運算符的完整列表,詳見Swift標準庫運算符參考
比較運算符
Swift提供所有標準C的比較運算符:
- 等于(
a == b
) - 不等于(
a != b
) - 大于(
a >b
) - 小于(
a < b
) - 大等于(
a >= b
) - 小等于(
a <= b
)
注意
Swift同樣提供了兩個恒等運算符 (===
和!==
),他們用來檢查兩個對象指針是否指向了同一個對象實例。查看更多信息,詳見類和結構體。
每個比較運算符都返回一個Bool
值來表示這個聲明是否為真:
1 == 1 // true because 1 is equal to 1
2 != 1 // true because 2 is not equal to 1
2 > 1 // true because 2 is greater than 1
1 < 2 // true because 1 is less than 2
1 >= 1 // true because 1 is greater than or equal to 1
2 <= 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".
想了解更多關于if
信息,詳見控制流。
你同樣也可以比較兩個有同樣數量值的元組,只要元組內的每個值都是可比較的。例如Int
和String
是可以比較的,這意味著(Int, String)
類型的元組是可比較的。與之相對,Bool
是不能比較的,所以包含布爾類型的元組是不可比較的。
元組從左到右逐一比較,直到找到兩個不同的值。這兩個值的比較結果作為整個元組的比較結果。如果所有元素都相等,那么元組就相等。例如:
(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")
,忽略了元組的其它值。無需關注"zebra"
小于"apple"
,因為比較結果已經被元祖的第一個元素決定了。但是當元組的第一個元素相同時,第二個元素就會被比較 ,像2,3行那樣。
注意
Swift標準庫提供的元組比較運算符只支持元組元素個數小于7個的情況。當大等于7個時,需要自己實現比較運算符。
三元條件運算符
三元條件運算符 是一個由三部分組成的特殊運算符,形式為question ? answer1 : answer2
。它是一個根據question
是否為真來選取兩個表達式其中之一的簡寫。如果為真,它選取answer1
并返回它的值,如果為假,選取answer2
并返回它的值。
三元條件運算符是以下形式代碼的簡寫:
if question {
answer1
} else {
answer2
}
下面的例子用來計算table的行高。如果這個行有頭部的話,行高要比contentHeight
高出50,否則高出20:
let contentHeight = 40
let hasHeader = true
let rowHeight = contentHeight + (hasHeader ? 50 : 20)
// rowHeight is equal to 90
上面的例子是下面代碼的簡寫:
let contentHeight = 40
let hasHeader = true
let rowHeight: Int
if hasHeader {
rowHeight = contentHeight + 50
} else {
rowHeight = contentHeight + 20
}
// rowHeight is equal to 90
第一個例子中三元條件運算符的使用讓rowHeight
可以用一行代碼搞定,這要比第二個例子簡潔的多。
三元條件運算符提供了處理二選一問題的高效方式。但是使用時也需要注意。如果過度使用,它的簡潔性會導致代碼難以閱讀。所以應該避免將多個三元條件運算符的實例組合在一個組合聲明中。
Nil聚合運算符
nil聚合運算符 (a ?? b)會解包可選型a
,如果a
包含一個值的話,否則返回默認值b
。a
永遠是一個可選類型。b
必須符合a
存儲的數據類型。
nil聚合運算符是以下代碼的簡寫:
a != nil ? a! : b
以上代碼使用三元條件運算符,當a
不是nil
時,強制解包(a!
)來獲取a
的解包值,否則返回b
。nil聚合運算符以一種簡潔和易讀的格式提供了一種更加優雅的方式來包裝這種條件檢查和解包工作。
注意
如果a
的值非nil
,那么b
的值不會被評估。這被稱為短路估值。
下面的例子使用nil聚合運算符在一種默認的顏色名和一個可選型的用戶自定義顏色中選擇一種:
let defaultColorName = "red"
var userDefinedColorName: String? // defaults to nil
var colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is nil, so colorNameToUse is set to the default of "red"
變量userDefinedColorName
被定義為一個默認值為nil
的可選型的String
。因為userDefinedColorName
是一個可選類型,你可以使用nil聚合運算符決定它的值。上面的例子中,這個運算符用來決定名為colorNameToUse
的String
型變量的值。因為userDefinedColorName
是nil
,表達式userDefinedColorName ?? defaultColorName
返回defaultColorName
的值,依舊是“red”
如果userDefinedColorName
被賦一個非nil
值再次執行nil聚合運算符檢查,userDefinedColorName
解包的值會取代默認值被使用:
userDefinedColorName = "green"
colorNameToUse = userDefinedColorName ?? defaultColorName
// userDefinedColorName is not nil, so colorNameToUse is set to "green"
區間運算符
Swift提供兩種區間運算符,它們用來簡化描述值的范圍。
閉區間運算符
閉區間運算符 (a...b
)定義了一個從a
到b
,并且包括a
和b
的范圍。a
的值必須小于b
的值。
當遍歷一個范圍內的所有值時,閉區間運算符非常有用,例如一個for-in
循環:
or 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
查看更多for-in
信息,詳見控制流。
半開區間運算符
半開區間運算符 (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("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
注意觀察數組包含4個元素,但是0..<count
只計數到3
(最后一個元素的索引),因為它是一個半開區間。更多關于數組信息,詳見數組。
邏輯運算符
邏輯運算符 修改或者組合布爾邏輯值true
和false
。Swift支持基于C語言的三種標準邏輯運算符:
- 邏輯非(
!a
) - 邏輯與(
a && b
) - 邏輯或(
a || b
)
邏輯非運算符
邏輯非運算符 (!a
)轉換一個布爾值,因此true
變為false
,false
變為true
。
邏輯非運算符是一個前置運算符,它會立刻出現在運算對象的前面,沒有任何空格。他可以被解讀為“不是一個”,像下面例子所示:
let allowedEntry = false
if !allowedEntry {
print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"
代碼片段if !allowedEntry
可以解讀為“如果不被允許進入”。接下來的代碼只會在“不允許進入”為真是執行。也就是說如果allowedEntry
為false
。
如上例所示,慎重選擇布爾常量或者變量名有助于保持代碼的可讀性和簡潔性,同樣的也要避免兩個負數或者令人疑惑的邏輯聲明。
邏輯與運算符
邏輯與運算符 (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")
}
// Prints "ACCESS DENIED"
邏輯或運算符
邏輯或運算符 (a || b
)是一個中置運算符,它由兩個毗鄰的豎線構成。當兩個值中的任何一個為真時,整個表達式就為真。
同上面的邏輯與運算符一樣,邏輯或運算符使用短路評估計算表達式。如果一個邏輯表達式的左邊為true
,右邊的表達式將不會計算,因為右邊的表達式已經不能改變整個表達式的結果。
在下面的例子中,第一個Bool
值(hasDoorKey
)為false
,但是第二個值(knowsOverridePassword
)為true
。因為有一個值為true
,所以整個表達式也被評估為true
,允許進入:
let hasDoorKey = false
let knowsOverridePassword = true
if hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
組合邏輯運算符
你可以組合多個邏輯運算符創建一個更長的組合表達式:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
這個例子使用多個&&
和||
運算符創建了一個更長的組合表達式。但是,&&
和||
運算符仍然只作用于兩個值,因此實際上是三個更小的表達式鏈接在了一起。這個例子可以解讀為:
如果我們輸入了正確的房間密碼并且通過了高清掃描,或者我們有一個合法的房門鑰匙,或者我們知道緊急重置密碼,那么就能打開房門。
根據enteredDoorCode
,passedRetinaScan
和hasDoorKey
的值,前兩個子表達式是false
,但是,我們知道緊急重置密碼,所以整個組合表達式仍然是true
。
注意
Swift的邏輯運算符&&
和||
是左結合的,也就是說包含多個邏輯運算符的復合表達式會首先評估最左邊的子表達式。
清晰的括號
有時為了使一個復雜的表達式易讀,引入括號是很有用的即使它們并不真的需要。在上面進入房間的例子中,為第一個組合表達式添加括號來使意圖明確是很有用的:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
print("Welcome!")
} else {
print("ACCESS DENIED")
}
// Prints "Welcome!"
這個括號使得前兩個值被看成整個邏輯中不同的可能狀態的一部分。組合表達式的結果并沒有改變,但是整個意圖變得清晰易讀。易讀性總是優先于簡潔性;使用括號來使你的意圖明確。
上一篇:Swift-基礎部分
下一篇:Swift-字符串和字符