運算符是檢查、改變、合併值的特殊符號或短語。例如,加號+
將兩個數相加(如let i = 1 + 2
)。更復雜的運算例子包括邏輯與運算符&&
(如if enteredDoorCode && passedRetinaScan
),或讓 i 值加1的便捷自增運算符++i
等。html
Swift 支持大部分標準 C 語言的運算符,且改進許多特性來減小常規編碼錯誤。如:賦值符(=
)不返回值,以防止把想要判斷相等運算符(==
)的地方寫成賦值符致使的錯誤。算術運算符(+
,-
,*
,/
,%
等)會檢測並不容許值溢出,以此來避免保存變量時因爲變量大於或小於其類型所能承載的範圍時致使的異常結果。固然容許你使用 Swift 的溢出運算符來實現溢出。詳情參見溢出運算符。swift
區別於 C 語言,在 Swift 中你能夠對浮點數進行取餘運算(%
),Swift 還提供了 C 語言沒有的表達兩數之間的值的區間運算符(a..<b
和a...b
),這方便咱們表達一個區間內的數值。數組
本章節只描述了 Swift 中的基本運算符,高級運算符包含了高級運算符,及如何自定義運算符,及如何進行自定義類型的運算符重載。ide
運算符有一元、二元和三元運算符。ui
一元運算符對單一操做對象操做(如-a
)。一元運算符分前置運算符和後置運算符,前置運算符需緊跟在操做對象以前(如!b
),後置運算符需緊跟在操做對象以後(如i++
)。編碼
二元運算符操做兩個操做對象(如2 + 3
),是中置的,由於它們出如今兩個操做對象之間。lua
三元運算符操做三個操做對象,和 C 語言同樣,Swift 只有一個三元運算符,就是三目運算符(a ? b : c
)。spa
受運算符影響的值叫操做數,在表達式1 + 2
中,加號+
是二元運算符,它的兩個操做數是值1
和2
。code
賦值運算(a = b
),表示用b
的值來初始化或更新a
的值:htm
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 並不返回任何值 }
這個特性使你沒法把(==
)錯寫成(=
),因爲if x = y
是錯誤代碼,Swift幫你避免此類錯誤的的發生。
Swift 中全部數值類型都支持了基本的四則算術運算:
加法(+
)
減法(-
)
乘法(*
)
除法(/
)
1 + 2 // 等於 3 5 - 3 // 等於 2 2 * 3 // 等於 6 10.0 / 2.5 // 等於 4.0
與 C 語言和 Objective-C 不一樣的是,Swift 默認狀況下不容許在數值運算中出現溢出狀況。可是你可使用 Swift 的溢出運算符來實現溢出運算(如a &+ b
)。詳情參見溢出運算符。
加法運算符也可用於String
的拼接:
"hello, " + "world" // 等於 "hello, world"
求餘運算(a % b
)是計算b
的多少倍剛恰好能夠容入a
,返回多出來的那部分(餘數)。
注意:
求餘運算(%
)在其餘語言也叫取模運算。然而嚴格說來,咱們看該運算符對負數的操做結果,"求餘"比"取模"更合適些。
咱們來談談取餘是怎麼回事,計算9 % 4
,你先計算出4
的多少倍會恰好能夠容入9
中:
2倍,很是好,那餘數是1(用橙色標出)
在 Swift 中能夠表達爲:
9 % 4 // 等於 1
爲了獲得a % b
的結果,%
計算了如下等式,並輸出餘數
做爲結果:
a = (b × 倍數) + 餘數
當倍數
取最大值的時候,就會恰好能夠容入a
中。
把9
和4
代入等式中,咱們得1
:
9 = (4 × 2) + 1
一樣的方法,咱們來計算 -9 % 4
:
-9 % 4 // 等於 -1
把-9
和4
代入等式,-2
是取到的最大整數:
-9 = (4 × -2) + -1
餘數是-1
。
在對負數b
求餘時,b
的符號會被忽略。這意味着 a % b
和 a % -b
的結果是相同的。
不一樣於 C 語言和 Objective-C,Swift 中是能夠對浮點數進行求餘的。
8 % 2.5 // 等於 0.5
這個例子中,8
除於2.5
等於3
餘0.5
,因此結果是一個Double
值0.5
。
和 C 語言同樣,Swift 也提供了對變量自己加1或減1的自增(++
)和自減(--
)的縮略算符。其操做對象能夠是整形和浮點型。
var i = 0 ++i // 如今 i = 1
每調用一次++i
,i
的值就會加1。實際上,++i
是i = i + 1
的簡寫,而--i
是i = i - 1
的簡寫。
++
和--
既能夠用做前置運算又能夠用做後置運算。++i
,i++
,--i
和i--
都是有效的寫法。
咱們須要注意的是這些運算符便可修改了i
的值也能夠返回i
的值。若是你只想修改i
的值,那你就能夠忽略這個返回值。但若是你想使用返回值,你就須要留意前置和後置操做的返回值是不一樣的,她們遵循如下原則:
當++
前置的時候,先自増再返回。
當++
後置的時候,先返回再自增。
例如:
var a = 0 let b = ++a // a 和 b 如今都是 1 let c = a++ // a 如今 2, 但 c 是 a 自增前的值 1
上述例子,let b = ++a
先把a
加1了再返回a
的值。因此a
和b
都是新值1
。
而let c = a++
,是先返回了a
的值,而後a
才加1。因此c
獲得了a
的舊值1,而a
加1後變成2。
除非你須要使用i++
的特性,否則推薦你使用++i
和--i
,由於先修改後返回這樣的行爲更符合咱們的邏輯。
數值的正負號可使用前綴-
(即一元負號)來切換:
let three = 3 let minusThree = -three // minusThree 等於 -3 let plusThree = -minusThree // plusThree 等於 3, 或 "負負3"
一元負號(-
)寫在操做數以前,中間沒有空格。
一元正號(+
)不作任何改變地返回操做數的值:
let minusSix = -6 let alsoMinusSix = +minusSix // alsoMinusSix 等於 -6
雖然一元+
什麼都不會改變,但當你在使用一元負號來表達負數時,你可使用一元正號來表達正數,如此你的代碼會具備對稱美。
如同 C 語言,Swift 也提供把其餘運算符和賦值運算(=
)組合的組合賦值運算符,組合加運算(+=
)是其中一個例子:
var a = 1 a += 2 // a 如今是 3
表達式a += 2
是a = a + 2
的簡寫,一個組合加運算就是把加法運算和賦值運算組合成進一個運算符裏,同時完成兩個運算任務。
注意:
複合賦值運算沒有返回值,let b = a += 2
這類代碼是錯誤。這不一樣於上面提到的自增和自減運算符。
全部標準 C 語言中的比較運算均可以在 Swift 中使用:
等於(a == b
)
不等於(a != b
)
大於(a > b
)
小於(a < b
)
大於等於(a >= b
)
小於等於(a <= b
)
注意: Swift 也提供恆等===
和不恆等!==
這兩個比較符來判斷兩個對象是否引用同一個對象實例。更多細節在類與結構。
每一個比較運算都返回了一個標識表達式是否成立的布爾值:
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"
關於if
語句,請看控制流。
三目運算符的特殊在於它是有三個操做數的運算符,它的原型是 問題 ? 答案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 var rowHeight = contentHeight if hasHeader { rowHeight = rowHeight + 50 } else { rowHeight = rowHeight + 20 } // rowHeight 如今是 90
第一段代碼例子使用了三目運算,因此一行代碼就能讓咱們獲得正確答案。這比第二段代碼簡潔得多,無需將rowHeight
定義成變量,由於它的值無需在if
語句中改變。
三目運算提供有效率且便捷的方式來表達二選一的選擇。須要注意的事,過分使用三目運算符會使簡潔的代碼變的難懂。咱們應避免在一個組合語句中使用多個三目運算符。
空合運算符(a ?? b
)將對可選類型a
進行空判斷,若是a
包含一個值就進行解封,不然就返回一個默認值b
.這個運算符有兩個條件:
表達式a
必須是Optional類型
默認值b
的類型必需要和a
存儲值的類型保持一致
空合運算符是對如下代碼的簡短表達方法
a != nil ? a! : b
上述代碼使用了三目運算符。當可選類型a
的值不爲空時,進行強制解封(a!
)訪問a
中值,反之當a
中值爲空時,返回默認值b。無疑空合運算符(??
)提供了一種更爲優雅的方式去封裝條件判斷和解封兩種行爲,顯得簡潔以及更具可讀性。
注意: 若是
a
爲非空值(non-nil
),那麼值b
將不會被估值。這也就是所謂的短路求值。
下文例子採用空合運算符,實現了在默認顏色名和可選自定義顏色名之間抉擇:
let defaultColorName = "red" var userDefinedColorName: String? //默認值爲 nil var colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName 的值爲空,因此 colorNameToUse 的值爲 "red"
userDefinedColorName
變量被定義爲一個可選String
類型,默認值爲nil
。因爲userDefinedColorName
是一個可選類型,咱們可使用空合運算符去判斷其值。在上一個例子中,經過空合運算符爲一個名爲colorNameToUse
的變量賦予一個字符串類型初始值。 因爲userDefinedColorName
值爲空,所以表達式userDefinedColorName ?? defaultColorName
返回defaultColorName
的值,即red
。
另外一種狀況,分配一個非空值(non-nil
)給userDefinedColorName
,再次執行空合運算,運算結果爲封包在userDefaultColorName
中的值,而非默認值。
userDefinedColorName = "green" colorNameToUse = userDefinedColorName ?? defaultColorName // userDefinedColorName 非空,所以 colorNameToUse 的值爲 "green"
Swift 提供了兩個方便表達一個區間的值的運算符。
閉區間運算符(a...b
)定義一個包含從a
到b
(包括a
和b
)的全部值的區間,b
必須大於等於a
。 閉區間運算符在迭代一個區間的全部值時是很是有用的,如在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
關於for-in
,請看控制流。
半開區間(a..<b
)定義一個從a
到b
但不包括b
的區間。 之因此稱爲半開區間,是由於該區間包含第一個值而不包括最後的值。
半開區間的實用性在於當你使用一個從0開始的列表(如數組)時,很是方便地從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
數組有4個元素,但0..<count
只數到3(最後一個元素的下標),由於它是半開區間。關於數組,請查閱數組。
邏輯運算的操做對象是邏輯布爾值。Swift 支持基於 C 語言的三個標準邏輯運算。
邏輯非(!a
)
邏輯與(a && b
)
邏輯或(a || b
)
邏輯非運算(!a
)對一個布爾值取反,使得true
變false
,false
變true
。
它是一個前置運算符,需緊跟在操做數以前,且不加空格。讀做非 a
,例子以下:
let allowedEntry = false if !allowedEntry { print("ACCESS DENIED") } // 輸出 "ACCESS DENIED"
if !allowedEntry
語句能夠讀做「若是非 allowedEntry。」,接下一行代碼只有在「非 allowedEntry」爲true
,即allowEntry
爲false
時被執行。
在示例代碼中,當心地選擇布爾常量或變量有助於代碼的可讀性,而且避免使用雙重邏輯非運算,或混亂的邏輯語句。
邏輯與(a && b
)表達了只有a
和b
的值都爲true
時,整個表達式的值纔會是true
。
只要任意一個值爲false
,整個表達式的值就爲false
。事實上,若是第一個值爲false
,那麼是不去計算第二個值的,由於它已經不可能影響整個表達式的結果了。這被稱作「短路計算(short-circuit evaluation)」。
如下例子,只有兩個Bool
值都爲true
的時候才容許進入:
let enteredDoorCode = true let passedRetinaScan = false if enteredDoorCode && passedRetinaScan { print("Welcome!") } else { print("ACCESS DENIED") } // 輸出 "ACCESS DENIED"
邏輯或(a || b
)是一個由兩個連續的|
組成的中置運算符。它表示了兩個邏輯表達式的其中一個爲true
,整個表達式就爲true
。
同邏輯與運算相似,邏輯或也是「短路計算」的,當左端的表達式爲true
時,將不計算右邊的表達式了,由於它不可能改變整個表達式的值了。
如下示例代碼中,第一個布爾值(hasDoorKey
)爲false
,但第二個值(knowsOverridePassword
)爲true
,因此整個表達是true
,因而容許進入:
let hasDoorKey = false let knowsOverridePassword = true if hasDoorKey || knowsOverridePassword { print("Welcome!") } else { print("ACCESS DENIED") } // 輸出 "Welcome!"
咱們能夠組合多個邏輯運算來表達一個複合邏輯:
if enteredDoorCode && passedRetinaScan || hasDoorKey || knowsOverridePassword { print("Welcome!") } else { print("ACCESS DENIED") } // 輸出 "Welcome!"
這個例子使用了含多個&&
和||
的複合邏輯。但不管怎樣,&&
和||
始終只能操做兩個值。因此這實際是三個簡單邏輯連續操做的結果。咱們來解讀一下:
若是咱們輸入了正確的密碼並經過了視網膜掃描,或者咱們有一把有效的鑰匙,又或者咱們知道緊急狀況下重置的密碼,咱們就能把門打開進入。
前兩種狀況,咱們都不知足,因此前兩個簡單邏輯的結果是false
,可是咱們是知道緊急狀況下重置的密碼的,因此整個複雜表達式的值仍是true
。
注意: Swift 邏輯操做符&&
和||
是左結合的,這意味着擁有多元邏輯操做符的複合表達式優先計算最左邊的子表達式。
爲了一個複雜表達式更容易讀懂,在合適的地方使用括號來明確優先級是頗有效的,雖然它並不是必要的。在上個關於門的權限的例子中,咱們給第一個部分加個括號,使它看起來邏輯更明確:
if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword { print("Welcome!") } else { print("ACCESS DENIED") } // 輸出 "Welcome!"
這括號使得前兩個值被當作整個邏輯表達中獨立的一個部分。雖然有括號和沒括號的輸出結果是同樣的,但對於讀代碼的人來講有括號的代碼更清晰。可讀性比簡潔性更重要,請在可讓你代碼變清晰的地方加個括號吧!