Swift-基礎運算符

運算符 是可以檢查,修改或者組合值的特殊符號或者短語。例如,加法運算符(+)將兩個數相加,像let i = 1 + 2,邏輯與運算符組合兩個布爾值,像if enteredDoorCode && passedRetinaScan
Swift支持大多數標準C運算符并且改善了一些功能來避免常見的編碼錯誤。賦值運算符(=)不會返回一個值,避免被錯誤的當成等于運算符(==)使用。數學運算符(+,-,*,/,%等等)會檢測并且不允許值溢出,避免使用一些過大或者過小以致超出存儲它們的類型允許范圍的值而導致意外的結果。可以通過使用Swift的溢出運算符來處理值溢出的情況,詳見溢出運算符
Swift同樣提供了兩個C沒有的區間運算符(a..<ba...b),作為描述區間值的簡寫。
本章講述Swift的基礎運算符。高級運算符章節會介紹Swift的高級運算符,并會介紹如何定義一個自定義運算符,以及為你的自定義類型實現運算符重載。

目錄

  • 術語
  • 賦值運算符
  • 數學運算符
  • 組合賦值運算符
  • 比較運算符
  • 三元條件運算符
  • Nil聚合運算符
  • 區間運算符
  • 邏輯運算符

術語

運算符可以是一元,二元者三元的:

  • 一元運算符作用于一個單獨對象(例如-a)。一元前置運算符出現在對象的前面(例如!b),一元后置運算符出現在對象的后面(例如c!)。
  • 二元運算符作用于兩個對象,是中置的,因為它出現在兩個對象中間。
  • 三元運算符作用于三個對象。和C一樣,Swift只有一個三元運算符:三元條件運算符(a ? b : c)。

運算符影響的值稱為運算對象。在表達式1 + 2中,符號+是一個二元運算符,它的兩個運算對象是值12

賦值運算符

賦值運算符(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的最大乘數。
94帶入等式,結果如下:
9 = (4 x 2) + 1
同樣的方法也是用于當a是一個負數時:

-9 % 4   // equals -1

-94帶入等式,結果如下:
-9 = (4 x -2) + -1
得出余數為-1
b是負數時符號可忽略,這意味著a % ba % -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 += 2a = 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信息,詳見控制流
你同樣也可以比較兩個有同樣數量值的元組,只要元組內的每個值都是可比較的。例如IntString是可以比較的,這意味著(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包含一個值的話,否則返回默認值ba永遠是一個可選類型。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聚合運算符決定它的值。上面的例子中,這個運算符用來決定名為colorNameToUseString型變量的值。因為userDefinedColorNamenil,表達式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)定義了一個從ab,并且包括ab的范圍。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)定義了一個從ab,但不包括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(最后一個元素的索引),因為它是一個半開區間。更多關于數組信息,詳見數組

邏輯運算符

邏輯運算符 修改或者組合布爾邏輯值truefalse。Swift支持基于C語言的三種標準邏輯運算符:

  • 邏輯非(!a)
  • 邏輯與(a && b)
  • 邏輯或(a || b)

邏輯非運算符

邏輯非運算符 (!a)轉換一個布爾值,因此true變為falsefalse變為true
邏輯非運算符是一個前置運算符,它會立刻出現在運算對象的前面,沒有任何空格。他可以被解讀為“不是一個”,像下面例子所示:

let allowedEntry = false
if !allowedEntry {
    print("ACCESS DENIED")
}
// Prints "ACCESS DENIED"

代碼片段if !allowedEntry可以解讀為“如果不被允許進入”。接下來的代碼只會在“不允許進入”為真是執行。也就是說如果allowedEntryfalse
如上例所示,慎重選擇布爾常量或者變量名有助于保持代碼的可讀性和簡潔性,同樣的也要避免兩個負數或者令人疑惑的邏輯聲明。

邏輯與運算符

邏輯與運算符 (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!"

這個例子使用多個&&||運算符創建了一個更長的組合表達式。但是,&&||運算符仍然只作用于兩個值,因此實際上是三個更小的表達式鏈接在了一起。這個例子可以解讀為:
如果我們輸入了正確的房間密碼并且通過了高清掃描,或者我們有一個合法的房門鑰匙,或者我們知道緊急重置密碼,那么就能打開房門。
根據enteredDoorCodepassedRetinaScanhasDoorKey的值,前兩個子表達式是false,但是,我們知道緊急重置密碼,所以整個組合表達式仍然是true

注意
Swift的邏輯運算符&&||是左結合的,也就是說包含多個邏輯運算符的復合表達式會首先評估最左邊的子表達式。

清晰的括號

有時為了使一個復雜的表達式易讀,引入括號是很有用的即使它們并不真的需要。在上面進入房間的例子中,為第一個組合表達式添加括號來使意圖明確是很有用的:

if (enteredDoorCode && passedRetinaScan) || hasDoorKey || knowsOverridePassword {
    print("Welcome!")
} else {
    print("ACCESS DENIED")
}
// Prints "Welcome!"

這個括號使得前兩個值被看成整個邏輯中不同的可能狀態的一部分。組合表達式的結果并沒有改變,但是整個意圖變得清晰易讀。易讀性總是優先于簡潔性;使用括號來使你的意圖明確。

上一篇:Swift-基礎部分
下一篇:Swift-字符串和字符

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,030評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,310評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,951評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,796評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,566評論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,055評論 1 322
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,142評論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,303評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,799評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,683評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,899評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,409評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,135評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,520評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,757評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,528評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,844評論 2 372

推薦閱讀更多精彩內容