? ? 運(yùn)算符是一個(gè)特殊的符號(hào)或者短句家卖,你可以用它來(lái)檢查,改變或者組合某一些值。比如飞主,加法運(yùn)算符(+)可以讓2個(gè)數(shù)字相加,像在?let i = 1 + 2 中一樣,有比如邏輯與運(yùn)算符(&&),可以組合2個(gè)布爾值琉朽,就像在 if??true && false?中一樣域帐。
? ? Swfit支持大多數(shù)標(biāo)準(zhǔn)c語(yǔ)言中的運(yùn)算符,還改善了部分功能,用以排除一些常見(jiàn)的編碼錯(cuò)誤悴侵。賦值運(yùn)算符(=)不會(huì)有返回值瞧剖,防止和比較運(yùn)算符(==)混用。術(shù)數(shù)運(yùn)算符(+,-*,/,%等)可免,會(huì)檢測(cè)并防止值溢出抓于。避免在正在處理的值不在對(duì)應(yīng)類型可以存儲(chǔ)的值的范圍之中而出現(xiàn)意料之外的結(jié)果。你可以選擇溢出運(yùn)算符來(lái)選擇值溢出是采取的行為浇借。
? ? Swift也提供了C語(yǔ)言中沒(méi)有的范圍運(yùn)算符捉撮,比如a..<b和a...b,這是表示值的范圍的簡(jiǎn)寫。
? ? 這一章只描述Swift中常用的運(yùn)算符妇垢。在高級(jí)運(yùn)算符章節(jié)中巾遭,會(huì)覆蓋Swift的高級(jí)運(yùn)算符,以及如何定義你自己的運(yùn)算符闯估,或者為你自定義的類實(shí)現(xiàn)標(biāo)準(zhǔn)庫(kù)中的運(yùn)算符灼舍。
術(shù)語(yǔ)(Terminology)
? ? 運(yùn)算符分為一元運(yùn)算符,二元運(yùn)算符睬愤,和三元運(yùn)算符:????
? ? 一元運(yùn)算符作用在一個(gè)單獨(dú)的目標(biāo)上片仿,比如(-a)。一元的前綴運(yùn)算符緊跟在要操作的目標(biāo)之前(!b)尤辱。一元的后綴運(yùn)算符緊跟在要操作的目標(biāo)之后(c!)。
? ? 二元運(yùn)算符作用在2個(gè)目標(biāo)上厢岂,比如2 + 3光督。被稱為中綴,因?yàn)樗霈F(xiàn)在2個(gè)目標(biāo)之間塔粒。
? ? 三元運(yùn)算符作用在3個(gè)目標(biāo)之上结借。和C語(yǔ)言一樣,Swift只有一個(gè)三元運(yùn)算符卒茬,也就是三目運(yùn)算符(a ??b : c)
? ? 運(yùn)算符操作的值叫做運(yùn)算單元船老。在表達(dá)式1 + 2中,+ 號(hào)運(yùn)算符是一個(gè)2元運(yùn)算符圃酵,它的2個(gè)運(yùn)算單元是值1和2柳畔。
賦值運(yùn)算符(Assignment Operator)
? ? 賦值運(yùn)算符(a = b)用來(lái)使用b的值初始化或者更新a的值。
? ??????let b = 10
????????var a = 5
????????a = b
????????// a 現(xiàn)在等于 10
? ? 如果賦值運(yùn)算符右邊是一個(gè)包含了多個(gè)值的元組郭赐,它的元素可以通過(guò)一次操作分出多個(gè)常量或者變量薪韩。
????????let (x, y) = (1, 2)?????????// x 等于 1, y 等于 2”
? ? 和C語(yǔ)言以及OC中不一樣,Swift中的賦值運(yùn)算符本身不會(huì)有返回值,所以下面的語(yǔ)句是無(wú)效的:
? ??????if x = y {?
????????? ? // 無(wú)效, 因?yàn)?x = y 沒(méi)有返回值.
????????}
? ? 這種特性可以防止賦值運(yùn)算符和相等比較運(yùn)算符(==)之間的誤用俘陷。通過(guò)是if x = y 無(wú)效罗捎,Swift可以防止在你的代碼中出現(xiàn)錯(cuò)誤。
術(shù)數(shù)運(yùn)算符(Arithmetic Operators)
? ? Swift為所有數(shù)字類型支持了4個(gè)基本的術(shù)數(shù)運(yùn)算符:
? ??????加法運(yùn)算符(+)? ??1 + 2 ?????// 3
? ? ? ? 減法運(yùn)算符(-)?? ??5 - 3 ????// 2
? ? ? ? 乘法運(yùn)算符(*)? ? ?2 * 3 ????// 6
? ? ? ? 除法運(yùn)算符(/) ? ?? 10.0 / 2.5 ????// 4.0
? ? 和C語(yǔ)言和OC中的術(shù)數(shù)運(yùn)算運(yùn)算符不一樣拉盾,Swift中的術(shù)數(shù)運(yùn)算符默認(rèn)不允許值溢出桨菜。可以使用Swift中值溢出運(yùn)算符來(lái)選擇值溢出的行為捉偏。
? ? 加法運(yùn)算符也要支持字符串的連接:
? ??????“hello, " + "world" ???? // 等于 "hello, world”
? 取余運(yùn)算符(Remainder Operator)
? ? 取余運(yùn)算符(a % b)計(jì)算出a里面可以包含多少個(gè)b,然后返回剩下的值,也就是余數(shù)雷激。
NOTE:取余運(yùn)算符(%)在其他語(yǔ)言中也被稱為模運(yùn)算符。然而嚴(yán)格來(lái)說(shuō),它是一個(gè)取余操作而不是取模操作告私。
? ? 9里面有2個(gè)4,所以余數(shù)是1屎暇。在Swift中,可以寫成: 9 % 4
? ? 取余運(yùn)算符使用下面的等式并且返回余數(shù)作為輸出驻粟,來(lái)決定 a % b 的結(jié)果:
? ??????a = (b x someMultiplier) + remainder
? ? 其中someMultiplier是a中可以有的最大的b的個(gè)數(shù)根悼,把9和4代入這個(gè)等式:
? ??????9 = (4 x 2) + 1
? ? 計(jì)算負(fù)數(shù)的時(shí)候使用的是同樣的計(jì)算公式:
? ? ? ? -9 % 4?? ??// -1?
? ? 把-9和4插入到上述的等式中:
? ??????-9 = (4 x -2) + -1
? ? 可以得到余數(shù)的值是-1
? ? 在公式中負(fù)數(shù)?b 的符號(hào)會(huì)被忽略。這就意味著 a % b 和 a % -b 的結(jié)果總是一樣的蜀撑。
一元減法運(yùn)算符(-)
? ? 數(shù)值可以使用前綴(-)挤巡,也就是一元減法運(yùn)算符:
? ??????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)算符并不做任何事情,但是你可以在一些使用了一元減法運(yùn)算符的代碼中使用一元加法運(yùn)算符來(lái)保持代碼的對(duì)稱沃饶。
符合賦值運(yùn)算符(Compound Assignment Operators)
????和C語(yǔ)言一樣母廷,Swift提供了混合賦值運(yùn)算符,也就是賦值運(yùn)算符和其他運(yùn)算符組合使用糊肤。一個(gè)例子就是加法混合運(yùn)算符(+=):
? ? var a = 1 ; a += 2 ????// a 等于 3
????表達(dá)式?a += 2 是 a = a + 2 的簡(jiǎn)寫琴昆。為了更高的效率,加法運(yùn)算符和復(fù)制運(yùn)算符被組合在成一個(gè)運(yùn)算符馆揉,一次執(zhí)行了2個(gè)任務(wù)业舍。
NOTE:混合運(yùn)算符沒(méi)有返回值,比如升酣, let b = a += 2 是不對(duì)的舷暮。
比較運(yùn)算符
? ? Swift提供了標(biāo)準(zhǔn)C語(yǔ)言所有的比較運(yùn)算符:
? ? ? ? 等于?(a == b)? ? ? ?? ? ? ? ? ? ??不等于 (a != b)
? ? ? ? 大于 (a > b)?? ???????????????? ? ? 小于 (a < b)
? ? ? ? 大于等于 to (a >= b)? ? ? ? ?小于等于 (a <= b)
NOTE:Swift還提供了2個(gè)恒等運(yùn)算符(===和!==),可以用來(lái)測(cè)試2個(gè)對(duì)象的引用是不是引用于同一個(gè)對(duì)象的實(shí)例噩茄。
? ? 每一個(gè)比較運(yùn)算符返回一個(gè)布爾值來(lái)表明表達(dá)式是不是成立下面。
? ? 比較運(yùn)算符通常會(huì)用在條件語(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", because name 等于 "world"
? ? 如果2個(gè)元組有相同的類型巢墅,也可以用比較運(yùn)算符比較诸狭。元組從左至右進(jìn)行比較券膀,一次比較一個(gè)值剿吻,直到比較結(jié)果不相等渣蜗。兩個(gè)對(duì)應(yīng)的值的比較,會(huì)決定整個(gè)元祖的比較的結(jié)果会涎。如果所有的元素都相等叉庐,那么元祖就是相等的舒帮,比如:
? ??????(1, "zebra") < (2, "apple") // true 因?yàn)?1 小于 2 ,后面的不比較
????????(3, "apple") < (3, "bird")? ? // true ?因?yàn)? 等于 3, "apple" 小于 "bird"
????????(4, "dog") == (4, "dog")? ? ? // true 因?yàn)?4 等于 4, and "dog" 等于 "dog”
? ? 上面的例子中,可以看見(jiàn)第一行從左往右進(jìn)行比較陡叠,因?yàn)?小于2玩郊,元組(1, "zebra")就被認(rèn)為小于元組(2, "apple"),無(wú)論元組中的其他值是什么枉阵。不會(huì)去考慮"zebra"并不小于"apple",因?yàn)榈谝粋€(gè)元素的的比較已經(jīng)決定了比較結(jié)果译红。然而,當(dāng)?shù)谝粋€(gè)元素比較結(jié)果相等的話兴溜,第二個(gè)元素就會(huì)被拿來(lái)比較侦厚,第二行和第三行就是這樣子做的。
? ? 只有在運(yùn)算符適用于元祖的每一個(gè)元素拙徽,元組才可以比較刨沦。比如下面的例子,可以比較 (String, Int)類型的元組膘怕,因?yàn)镾tring和Int都可以用 < 運(yùn)算符比較想诅。相對(duì)的,(String, Bool)類型的元組就不可以用 < 運(yùn)算符比較岛心,因?yàn)椴紶栔挡豢梢允褂?lt; 運(yùn)算符来破。
? ??????("blue", -1) < ("purple", 1) ?// OK, evaluates to true
????????("blue", false) < ("purple", true)? // 錯(cuò)誤,小于運(yùn)算符不適用于布爾值
NOTE:Swift標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)的元祖比較符只支持元素個(gè)數(shù)小于7個(gè)的元素。如果希望比較7個(gè)或者更多的元素的元組鹉梨,你需要自己實(shí)現(xiàn)比較運(yùn)算符讳癌。
三元條件運(yùn)算符(Ternary Conditional Operator)
? ??三元條件運(yùn)算符是一個(gè)包括了三個(gè)部分的特殊的元素的特殊的運(yùn)算符,就像這樣:?question ? answer1 : answer2
? ? 這是一種簡(jiǎn)潔代碼的方式存皂,它根據(jù)question的結(jié)果去決定是執(zhí)行answer1還是answer2,如果question的結(jié)果是true逢艘,會(huì)執(zhí)行并返回answer1的返回值旦袋,如果question的結(jié)果是false,會(huì)執(zhí)行并返回answer2的返回值它改。
?? ?三元條件運(yùn)算符是下面代碼的簡(jiǎn)寫:
????????if question {
????????? ? answer1
????????} else {
????????? ? answer2
????????}
? ? 在有2個(gè)表達(dá)式需要考慮的情況下疤孕,三木運(yùn)算提供了非常有效的簡(jiǎn)寫方式。然而央拖,請(qǐng)謹(jǐn)慎使用三木運(yùn)算祭阀,它很簡(jiǎn)潔鹉戚,但是過(guò)度使用付出的代價(jià)是難以閱讀。在一些混合語(yǔ)句中盡量避免使用三木運(yùn)算专控。
空合運(yùn)算符(Nil-Coalescing Operator)
????空合運(yùn)算符(a ?? b)抹凳,如果可選值a有值,解包a并且返回a解包后的值,如果a沒(méi)有值,返回默認(rèn)值b伦腐。表達(dá)式中的a是一個(gè)可選值赢底,b和a解包后的值的類型一樣。
? ? 空合運(yùn)算符下面代碼的簡(jiǎn)寫:
? ? ? ? a ?!= ?nil ? a! : b ? // (?a ?!= ?nil)中? != 是一個(gè)整體, ?而不是 a柏蘑!是一個(gè)整體P叶场!
? ? 上面的代碼使用了三目運(yùn)算符和強(qiáng)制解包去訪問(wèn)a中包含的值,當(dāng)a是nil的時(shí)候就返回b咳焚∏⑺穑空合運(yùn)算符以一種優(yōu)雅的方式,使得條件判斷和解包的操作可以用更精簡(jiǎn)和易讀的形式組合在了一起革半。
NOTE:如果a的值不是nil碑定,b的值不會(huì)被求值。也就是所謂的短路求值督惰。
? ? 下面的例子使用空合運(yùn)算符在默認(rèn)的顏色和用戶定義的顏色之間做選擇:
? ??????let defaultColorName = "red"
????????var userDefinedColorName: String?? // 默認(rèn)是nil
????????var colorNameToUse = userDefinedColorName ?? defaultColorName
????????// userDefinedColorName is nil, 所以使用默認(rèn)值?defaultColorName ?"red"
? ? 變量userDefinedColorName被定義為可選的String類型不傅,默認(rèn)是nil。因?yàn)?b>userDefinedColorName是可選值赏胚,所以可以在考慮它的值的時(shí)候使用空合運(yùn)算访娶。上面的例子中,空合運(yùn)算是為了決定變量colorNameToUse的初始值觉阅,因?yàn)?b>userDefinedColorName是nil崖疤,表示式userDefinedColorName ?? defaultColorName返回defaultColorName的值,也就是"red"典勇。
? ? 如果給可選變量userDefinedColorName賦予一個(gè)非空的值劫哼,然后再執(zhí)行空合運(yùn)算,將不會(huì)返回默認(rèn)值割笙,而是返回userDefinedColorName中包含的值权烧。
? ??????userDefinedColorName = "green"
????????colorNameToUse = userDefinedColorName ?? defaultColorName
????????// userDefinedColorName 不是 nil, 所以colorNameToUse現(xiàn)在是"green"