案例代碼下載
高級(jí)運(yùn)算符
除了基本運(yùn)算符中描述的運(yùn)算符之外饺鹃,Swift還提供了幾個(gè)執(zhí)行更復(fù)雜值操作的高級(jí)運(yùn)算符粱檀。這些包括C和Objective-C中熟悉的所有按位和位移運(yùn)算符蝇刀。
與C中的算術(shù)運(yùn)算符不同搓萧,Swift中的算術(shù)運(yùn)算符默認(rèn)不會(huì)溢出毛甲。溢出行為被捕獲并報(bào)告為錯(cuò)誤。要選擇溢出行為饲帅,請(qǐng)使用Swift默認(rèn)溢出的第二組算術(shù)運(yùn)算符复凳,例如溢出加法運(yùn)算符(&+)瘤泪。所有這些溢出運(yùn)算符都以&符號(hào)開頭灶泵。
定義自己的結(jié)構(gòu),類和枚舉時(shí)对途,為這些自定義類型提供自己的標(biāo)準(zhǔn)Swift運(yùn)算符實(shí)現(xiàn)會(huì)很有用赦邻。Swift可以輕松地為這些運(yùn)算符提供定制的實(shí)現(xiàn),并確切地確定它們對(duì)創(chuàng)建的每種類型的行為实檀。
不僅限于預(yù)定義的運(yùn)算符惶洲。Swift為提供了自定義中綴,前綴膳犹,后綴和賦值運(yùn)算符的自由恬吕,具有自定義優(yōu)先級(jí)和關(guān)聯(lián)性。這些運(yùn)算符可以像任何預(yù)定義的運(yùn)算符一樣在代碼中使用和采用须床,甚至可以擴(kuò)展現(xiàn)有類型以支持定義的自定義運(yùn)算符婚夫。
按位運(yùn)算符
按位運(yùn)算符可以處理數(shù)據(jù)結(jié)構(gòu)中的各個(gè)原始數(shù)據(jù)位轩勘。它們通常用于低級(jí)編程,例如圖形編程和設(shè)備驅(qū)動(dòng)程序創(chuàng)建。當(dāng)使用來自外部源的原始數(shù)據(jù)時(shí)稚叹,按位運(yùn)算符也很有用,例如編碼和解碼數(shù)據(jù)以通過自定義協(xié)議進(jìn)行通信东跪。
Swift支持C中的所有按位運(yùn)算符子眶,如下所述。
按位NOT運(yùn)算符
該位NOT運(yùn)算符(~)反轉(zhuǎn)數(shù)所有位:
按位NOT運(yùn)算符是一個(gè)前綴運(yùn)算符坦刀,它出現(xiàn)在它操作的值之前愧沟,沒有任何空格:
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits
UInt8整數(shù)有八位,可以存儲(chǔ)0和255之間的任何值鲤遥。此示例使用二進(jìn)制值初始化一個(gè)UInt8整數(shù)沐寺,該二進(jìn)制值00001111的前四位設(shè)置為0,其后四位設(shè)置為1渴频。這相當(dāng)于十進(jìn)制值15芽丹。
然后使用按位NOT運(yùn)算符創(chuàng)建一個(gè)新的常量invertedBits,該常量等于initialBits卜朗,但所有位都被反轉(zhuǎn)拔第。0成為1咕村,1成為0。invertedBitsis的值11110000等于無符號(hào)十進(jìn)制值240蚊俺。
按位AND運(yùn)算符
按位AND運(yùn)算符(&)結(jié)合了兩個(gè)數(shù)字的位數(shù)懈涛。它返回一個(gè)新的號(hào)碼,僅當(dāng)位兩個(gè)輸入數(shù)字在其位等于1才被設(shè)置為1:
在下面的例子中泳猬,firstSixBits和lastSixBits兩個(gè)值具有四個(gè)中間位等于1批钠。按位AND運(yùn)算符將它們組合起來以產(chǎn)生數(shù)字00111100,該數(shù)字等于無符號(hào)十進(jìn)制值60:
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits
按位OR運(yùn)算符
按位或運(yùn)算符(|)對(duì)兩個(gè)數(shù)的二進(jìn)制位進(jìn)行比較得封。運(yùn)算符返回一個(gè)新數(shù)字埋心,如果任一輸入數(shù)的位等于1其位設(shè)置為1:
在下面的例子中,someBits和moreBits的值具有不同的位設(shè)置為1忙上。按位OR運(yùn)算符將它們組合起來以產(chǎn)生數(shù)字11111110拷呆,該數(shù)字等于無符號(hào)數(shù)254:
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits
按位異或運(yùn)算符
的按位異或運(yùn)算符,或“異或運(yùn)算符”( ^)疫粥,比較兩個(gè)數(shù)的位茬斧。運(yùn)算符返回一個(gè)新數(shù)字,輸入位不同其位設(shè)置為1梗逮,輸入位相同其位設(shè)置為0:
在下面的示例中项秉,firstBits和otherBits一個(gè)值位為1,而另一個(gè)不是慷彤,按位異或運(yùn)算符這個(gè)位設(shè)置1為其輸出值娄蔼。firstBits和otherBits所有其他位相同在輸出值中設(shè)置為0:
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits
按位左右移位運(yùn)算符
在按位左移位運(yùn)算符(<<)和按位右移位運(yùn)算符(>>)中的數(shù)向左或向移動(dòng)一個(gè)數(shù)的所有特定數(shù)量的位,根據(jù)下面定義的規(guī)則瞬欧。
按位左右移位具有將整數(shù)乘以或除以因子2的效果贷屎。將整數(shù)位向左移動(dòng)一個(gè)位置會(huì)使其值加倍,而將其向右移動(dòng)一個(gè)位置會(huì)使其值減半艘虎。
無符號(hào)整數(shù)的移位行為
無符號(hào)整數(shù)的位移行為如下:
- 現(xiàn)有位按所請(qǐng)求的位數(shù)向左或向右移動(dòng)唉侄。
- 移除超出整數(shù)存儲(chǔ)邊界的任何位都將被丟棄。
- 在原始位向左或向右移動(dòng)之后野建,將零插入到留下的空間中属划。
這種方法被稱為邏輯轉(zhuǎn)換。
下圖顯示了11111111 << 1(11111111按位向左移動(dòng)1)和11111111 >> 1(11111111按位向右移動(dòng)1)的結(jié)果候生。移動(dòng)藍(lán)色數(shù)字同眯,丟棄灰色數(shù)字,并插入橙色零:
以下是Swift代碼中位移的方式:
let shiftBits: UInt8 = 4 // 00000100
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
可以使用位移來編碼和解碼其他數(shù)據(jù)類型中的值:
let pink: UInt32 = 0xCC6699
let redComponent = (pink & 0xFF0000) >> 16 // redComponent 是 0xCC, 即204
let greenComponent = (pink & 0x00FF00) >> 8 // greenComponent 是 0x66, 即102
let blueComponent = pink & 0x0000FF // blueComponent 是 0x99, 即153
此示例使用一個(gè)UInt32常量叫做pink來存儲(chǔ)顏色層疊樣式表的粉紅色顏色值唯鸭。CSS顏色值#CC6699寫0xCC6699在Swift的十六進(jìn)制數(shù)字表示中须蜗。然后通過按位AND運(yùn)算符(&)和按位右移運(yùn)算符(>>)將此顏色分解為其紅色(CC),綠色(66)和藍(lán)色(99)分量。
通過在數(shù)字0xCC6699和0xFF0000之間執(zhí)行按位AND來獲得紅色分量明肮。0xFF0000的0有效地“掩蓋”0xCC6699第二個(gè)和第三個(gè)字節(jié)菱农,導(dǎo)致6699被忽略返回0xCC0000。
然后將此數(shù)字向右移動(dòng)16位(>> 16)柿估。十六進(jìn)制數(shù)中的每對(duì)字符使用8位循未,因此向右移動(dòng)16位將0xCC0000轉(zhuǎn)換為0x0000CC。這與0xCC相同十進(jìn)制值204秫舌。
類似地的妖,綠色成分通過0xCC6699和0x00FF00之間執(zhí)行按位與數(shù)字獲得,其給出的輸出值0x006600足陨。然后將此輸出值向右移動(dòng)8位嫂粟,給出一個(gè)值0x66,其值為十進(jìn)制值102钠右。
最后赋元,將藍(lán)色成分是通過數(shù)字0xCC6699和0x0000FF之間執(zhí)行按位與獲得,其給出的輸出值0x000099飒房。沒有必要將它向右移動(dòng),因?yàn)?x000099等于0x99媚值,其十進(jìn)制值為153狠毯。
有符號(hào)整數(shù)的移位行為
對(duì)于有符號(hào)整數(shù)而言,移位行為比無符號(hào)整數(shù)更復(fù)雜褥芒,因?yàn)橛蟹?hào)整數(shù)用二進(jìn)制表示嚼松。(為簡(jiǎn)單起見,下面的示例基于8位有符號(hào)整數(shù)锰扶,但相同的原則適用于任何大小的有符號(hào)整數(shù)献酗。)
有符號(hào)整數(shù)使用它們的第一位(稱為符號(hào)位)來指示整數(shù)是正還是負(fù)。符號(hào)位0表示正數(shù)坷牛,符號(hào)1表示負(fù)數(shù)罕偎。
其余位(稱為值位)存儲(chǔ)實(shí)際值。正數(shù)以與無符號(hào)整數(shù)完全相同的方式存儲(chǔ)京闰,從0向上計(jì)數(shù)颜及。以下是數(shù)字4的Int8位數(shù):
符號(hào)位是0(意思是“正”),七個(gè)值位是用二進(jìn)制表示法寫的數(shù)字4蹂楣。
但是俏站,負(fù)數(shù)以不同方式存儲(chǔ)。它們的存儲(chǔ)方式是將它們的絕對(duì)值減去2的n次方痊土,其中n是值的位數(shù)肄扎。一個(gè)八比特?cái)?shù)有七個(gè)值的位,所以這意味著2的7次方,即128犯祠。
以下是Int8查找數(shù)字的位數(shù)-4:
這一次萌丈,符號(hào)位是1(意思是“負(fù)”),七個(gè)值位的二進(jìn)制值為124(即128 - 4):
負(fù)數(shù)的這種編碼稱為二進(jìn)制補(bǔ)碼表示雷则。這似乎是一種代表負(fù)數(shù)的不尋常方式辆雾,但它有幾個(gè)優(yōu)點(diǎn)。
首先月劈,可以-1加-4度迂,簡(jiǎn)單地通過執(zhí)行一個(gè)標(biāo)準(zhǔn)二進(jìn)制加法全部八個(gè)位(包括符號(hào)位),并丟棄任何不適合8位猜揪,一旦完成:
其次惭墓,二進(jìn)制補(bǔ)碼表示還可以將負(fù)數(shù)位向左和向右移動(dòng),就像正數(shù)一樣而姐,并且對(duì)于向左移動(dòng)的每一個(gè)移位最終都會(huì)將它們加倍腊凶,或者對(duì)于向右移動(dòng)的每個(gè)位將它們減半。 拴念。當(dāng)有符號(hào)整數(shù)右移钧萍,適用無符號(hào)整數(shù)相同的規(guī)則,但在剩下的填充任何空位:要做到這一點(diǎn)政鼠,整數(shù)右移使用符號(hào)位補(bǔ)位风瘦,而不是零。
此操作可確保有符號(hào)整數(shù)在向右移動(dòng)后具有相同的符號(hào)公般,并稱為算術(shù)移位万搔。
由于存儲(chǔ)正數(shù)和負(fù)數(shù)的特殊方式,將它們中的任何一個(gè)向右移動(dòng)都會(huì)使它們接近零官帘。在此移位期間保持符號(hào)位相同意味著負(fù)整數(shù)向0移動(dòng)保持為負(fù)值瞬雹。
溢出運(yùn)算符
如果嘗試將數(shù)字插入到不能保存該值的整數(shù)常量或變量中,默認(rèn)情況下Swift會(huì)報(bào)告錯(cuò)誤刽虹,而不是允許創(chuàng)建無效值酗捌。當(dāng)處理太大或太小的數(shù)字時(shí),此行為可提供額外的安全性状婶。
例如意敛,Int16整數(shù)類型可以包含-32768和32767之間的任何有符號(hào)整數(shù)。嘗試將Int16常量或變量設(shè)置為此范圍之外的數(shù)字會(huì)導(dǎo)致錯(cuò)誤:
var potentialOverflow = Int16.max
potentialOverflow += 1
當(dāng)值變得太大或太小時(shí)提供錯(cuò)誤處理膛虫,在編碼邊界值條件時(shí)提供更大的靈活性草姻。
但是,如果特別希望溢出條件截?cái)嗫捎梦粩?shù)稍刀,則可以選擇此行為而不是觸發(fā)錯(cuò)誤撩独。Swift提供了三個(gè)算術(shù)溢出運(yùn)算符敞曹,它們選擇加入整數(shù)計(jì)算的溢出行為。這些運(yùn)算符都以&符號(hào)開頭&:
- 溢出加法(&+)
- 溢出減法(&-)
- 溢出乘法(&*)
值溢出
數(shù)字可以在正方向和負(fù)方向上溢出综膀。
下面是使用overflow溢出加法(&+)允許無符號(hào)整數(shù)向正方向溢出時(shí)會(huì)發(fā)生什么的示例:
var unsignedOverflow = UInt8.max
unsignedOverflow = unsignedOverflow &+ 1
變量unsignedOverflow初始化為UInt8可以容納的最大值(255或二進(jìn)制11111111)澳迫。然后使用溢出加法運(yùn)算符(&+)遞增1。這使得它的二進(jìn)制表示超出了UInt8可以容納的大小剧劝,導(dǎo)致它溢出超出其邊界橄登,如下圖所示。UInt8溢出添加后保留在范圍內(nèi)的值00000000為零讥此。
當(dāng)允許無符號(hào)整數(shù)向負(fù)方向溢出時(shí)會(huì)發(fā)生類似情況拢锹。這是使用溢出減法運(yùn)算符(&-)的示例:
var unsignedOverflow = UInt8.min
unsignedOverflow = unsignedOverflow &- 1
UInt8可容納的最小值為零或00000000二進(jìn)制。如果使用溢出減法運(yùn)算符(&-)從00000000減去1萄喳,這個(gè)數(shù)字將溢出并環(huán)繞到11111111卒稳,或十進(jìn)制255。
對(duì)于有符號(hào)整數(shù)他巨,也會(huì)發(fā)生溢出充坑。有符號(hào)整數(shù)的所有加法和減法以按位方式執(zhí)行,符號(hào)位作為加數(shù)或減數(shù)的一部分包括在內(nèi)染突,如按位左右移位運(yùn)算符中所述捻爷。
var signedOverflow = Int8.min
signedOverflow = signedOverflow &- 1
Int8最小值為-128或二進(jìn)制10000000。使用溢出運(yùn)算符從此二進(jìn)制數(shù)中減去1得到二進(jìn)制01111111觉痛,該值將切換符號(hào)位得出正數(shù)127役衡,Int8即可容納的最大正值。
對(duì)于有符號(hào)和無符號(hào)整數(shù)薪棒,正方向上的溢出從最大有效整數(shù)值回到最小值,而負(fù)方向上的溢出從最小值回到最大值榕莺。
優(yōu)先級(jí)和相關(guān)性
運(yùn)算符優(yōu)先級(jí)使某些運(yùn)算符的優(yōu)先級(jí)高于其他俐芯, 那么首先計(jì)數(shù)優(yōu)先級(jí)高的運(yùn)算符。
運(yùn)算符關(guān)聯(lián)性定義了相同優(yōu)先級(jí)的運(yùn)算符如何組合在一起 - 從左側(cè)分組钉鸯,或從右側(cè)分組吧史。可以把它想象成“他們與左邊的表達(dá)聯(lián)系起來”或“他們將表達(dá)聯(lián)系到他們的右邊”和泌。
在計(jì)算復(fù)合表達(dá)式的順序時(shí)镐躲,考慮每個(gè)運(yùn)算符的優(yōu)先級(jí)和關(guān)聯(lián)性非常重要惑申。例如,運(yùn)算符優(yōu)先級(jí)解釋了以下表達(dá)式等于17的原因钞脂。
2 + 3 % 4 * 5
如果從左到右嚴(yán)格閱讀,可能表達(dá)式計(jì)算如下:
- 2加上3等于5
- 5余數(shù)4等于1
- 1時(shí)間5等于5
但是捕儒,實(shí)際答案17不是5冰啃。優(yōu)先級(jí)較高的運(yùn)算符在優(yōu)先級(jí)較低的運(yùn)算符之前進(jìn)行求值邓夕。在Swift中,與在C中一樣阎毅,余數(shù)運(yùn)算符(%)和乘法運(yùn)算符(*)的優(yōu)先級(jí)高于加法運(yùn)算符(+)焚刚。結(jié)果是在加法之前計(jì)數(shù)它們。
但是扇调,余數(shù)和乘法具有相同的優(yōu)先級(jí)矿咕。要得出確切計(jì)算順序,還需要考慮它們的相關(guān)性狼钮。余數(shù)和乘法都與左邊的表達(dá)式相關(guān)聯(lián)碳柱。可以想象這是在表達(dá)式的這些部分周圍添加隱式括號(hào)燃领,從左邊開始:
2 + ((3 % 4) * 5)
(3 % 4)是的3士聪,所以這相當(dāng)于:
2 + (3 * 5)
(3 * 5)是的15,所以這相當(dāng)于:
2 + 15
這個(gè)計(jì)算得出了最終答案17猛蔽。
有關(guān)Swift標(biāo)準(zhǔn)庫提供的運(yùn)算符的信息剥悟,包括運(yùn)算符優(yōu)先級(jí)組和相關(guān)性設(shè)置的完整列表,請(qǐng)參閱運(yùn)算符聲明曼库。
注意
Swift的運(yùn)算符優(yōu)先級(jí)和關(guān)聯(lián)性規(guī)則比C和Objective-C中的更簡(jiǎn)單区岗,更可預(yù)測(cè)。但是毁枯,這意味著它們與基于C的語言不完全相同慈缔。在將現(xiàn)有代碼移植到Swift時(shí),請(qǐng)務(wù)必確保運(yùn)算符交互的行為方式仍然符合預(yù)期种玛。
運(yùn)算符方法
類和結(jié)構(gòu)可以提供自己的現(xiàn)有運(yùn)算符實(shí)現(xiàn)藐鹤。這稱為重載現(xiàn)有運(yùn)算符。
下面的示例顯示了如何為自定義結(jié)構(gòu)實(shí)現(xiàn)算術(shù)加法運(yùn)算符(+)赂韵。算術(shù)加法運(yùn)算符是一個(gè)二元運(yùn)算符娱节,因?yàn)樗趦蓚€(gè)目標(biāo)上運(yùn)行,并且被稱為中綴祭示,因?yàn)樗霈F(xiàn)在這兩個(gè)目標(biāo)之間肄满。
該示例定義了二維位置向量(x, y)的結(jié)構(gòu)Vector2D,然后定義了將Vector2D結(jié)構(gòu)實(shí)例相加的運(yùn)算符方法:
struct Vector2D {
var x = 0.0, y = 0.0
}
extension Vector2D {
static func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
}
運(yùn)算符方法被定義為Vector2D的一個(gè)類型方法质涛,其方法名稱與要重載的運(yùn)算符(+)匹配稠歉。因?yàn)榧臃ú皇窍蛄康幕拘袨榈囊徊糠郑灶愋头椒ㄊ窃跀U(kuò)展Vector2D而不是在主結(jié)構(gòu)聲明中定義的Vector2D汇陆。因?yàn)樗阈g(shù)加法運(yùn)算符是二元運(yùn)算符怒炸,所以此運(yùn)算符方法接受兩個(gè)Vector2D類型的輸入?yún)?shù),并返回單個(gè)輸出值瞬测,也是類型Vector2D横媚。
在此實(shí)現(xiàn)中纠炮,輸入?yún)?shù)被命名left和right表示將位于+運(yùn)算符左側(cè)和右側(cè)的Vector2D實(shí)例。該方法返回一個(gè)新Vector2D實(shí)例灯蝴,其x和y屬性被從兩個(gè)Vector2D實(shí)例的x和y屬性加到一起的總和初始化恢口。
類型方法可以用作現(xiàn)有Vector2D實(shí)例之間的中綴運(yùn)算符:
let vector = Vector2D(x: 3.0, y: 1.0)
let anotherVector = Vector2D(x: 2.0, y: 4.0)
let combinedVector = vector + anotherVector
此示例將向量加在一起并生成向量,如下所示穷躁。(3.0, 1.0)(2.0, 4.0)(5.0, 5.0)
前綴和后綴運(yùn)算符
上面顯示的示例演示了二元中綴運(yùn)算符的自定義實(shí)現(xiàn)耕肩。類和結(jié)構(gòu)還可以提供標(biāo)準(zhǔn)一元運(yùn)算符的實(shí)現(xiàn)。一元運(yùn)算符在單個(gè)目標(biāo)上運(yùn)行问潭。如果它們位于其目標(biāo)(如)之前猿诸,則它們是前綴,如果它們?cè)谀繕?biāo)之后(例如-a)狡忙,則它們是后綴運(yùn)算符(如b!)梳虽。
通過在聲明運(yùn)算符方法時(shí)在func前寫入關(guān)鍵字prefixor、postfix修飾符來實(shí)現(xiàn)前綴或后綴一元運(yùn)算符:
extension Vector2D {
static prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
}
上面的示例為Vector2D實(shí)例實(shí)現(xiàn)了一元負(fù)運(yùn)算符(-a)灾茁。一元負(fù)運(yùn)算符是前綴運(yùn)算符窜觉,因此必須使用prefix修飾符限定此方法。
對(duì)于簡(jiǎn)單的數(shù)值北专,一元負(fù)運(yùn)算符將正數(shù)轉(zhuǎn)換為負(fù)數(shù)禀挫,反之亦然。Vector2D實(shí)例的相應(yīng)實(shí)現(xiàn)對(duì)x和y屬性執(zhí)行此操作:
let positive = Vector2D(x: 3.0, y: 4.0)
let negative = -positive
let alsoPositive = -negative
復(fù)合賦值運(yùn)算符
復(fù)合賦值運(yùn)算符將(=)與另一個(gè)運(yùn)算符相結(jié)合拓颓。例如语婴,加法賦值運(yùn)算符(+=)將加法和賦值組合到單個(gè)操作中。將復(fù)合賦值運(yùn)算符的左輸入?yún)?shù)類型標(biāo)記為inout驶睦,因?yàn)閰?shù)的值將直接從運(yùn)算符方法中修改砰左。
下面的示例為Vector2D實(shí)例實(shí)現(xiàn)了一個(gè)加法賦值運(yùn)算符方法:
extension Vector2D {
static func += (left: inout Vector2D, right: Vector2D) {
left = left + right
}
}
由于之前已定義了加法運(yùn)算符,因此無需在此處重新實(shí)現(xiàn)加法過程场航。相反菜职,加法賦值運(yùn)算符方法利用現(xiàn)有的加法運(yùn)算符方法,并使用它將左值設(shè)置為左值加右值:
var original = Vector2D(x: 1.0, y: 2.0)
let vectorToAdd = Vector2D(x: 3.0, y: 4.0)
original += vectorToAdd
注意
無法重載默認(rèn)賦值運(yùn)算符(=)旗闽。只有復(fù)合賦值運(yùn)算符才能重載。類似地蜜另,三元條件運(yùn)算符(a ? b : c)不能重載适室。
等價(jià)運(yùn)算符
默認(rèn)情況下,自定義類和結(jié)構(gòu)沒有等價(jià)運(yùn)算符的實(shí)現(xiàn)举瑰,稱為等于運(yùn)算符( == )和不等于 運(yùn)算符( != )捣辆。通常實(shí)現(xiàn)運(yùn)算符==,并使用標(biāo)準(zhǔn)庫的運(yùn)算符 != 來否定運(yùn)算符 == 的結(jié)果的默認(rèn)實(shí)現(xiàn)此迅。有兩種方法可以實(shí)現(xiàn)==運(yùn)算符:可以自己實(shí)現(xiàn)它汽畴,或者對(duì)于許多類型旧巾,可以讓Swift來實(shí)現(xiàn)。在這兩種情況下忍些,都可以遵守標(biāo)準(zhǔn)庫Equatable協(xié)議鲁猩。
以與實(shí)現(xiàn)其他中綴運(yùn)算符相同的方式提供==運(yùn)算符的實(shí)現(xiàn):
extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}
上面的示例實(shí)現(xiàn)了一個(gè)==運(yùn)算符來檢查兩個(gè)Vector2D實(shí)例是否具有等效值。在上下文中Vector2D罢坝,將“相等”視為“兩個(gè)實(shí)例具有相同的x值和y值” 廓握,因此這是運(yùn)算符實(shí)現(xiàn)所使用的邏輯。
現(xiàn)在可以使用此運(yùn)算符來檢查兩個(gè)Vector2D實(shí)例是否相等:
let twoThree = Vector2D(x: 2.0, y: 3.0)
let anotherTwoThree = Vector2D(x: 2.0, y: 3.0)
if twoThree == anotherTwoThree {
print("These two vectors are equivalent.")
}
在許多簡(jiǎn)單的情況下嘁酿,可以讓Swift為提供等價(jià)運(yùn)算符的綜合實(shí)現(xiàn)隙券。Swift為以下類型的自定義類型提供了綜合實(shí)現(xiàn):
- 僅存儲(chǔ)遵守Equatable協(xié)議的屬性的結(jié)構(gòu)
- 只包含遵守Equatable協(xié)議的關(guān)聯(lián)類型的枚舉
- 沒有關(guān)聯(lián)類型的枚舉
要接收綜合實(shí)現(xiàn)的==,在包含原始聲明的文件中聲明遵守Equatable闹司,而不是自己實(shí)現(xiàn)==操作符娱仔。
下面的示例定義了三維位置矢量(x, y, z)的結(jié)構(gòu)Vector3D,類似于結(jié)構(gòu)Vector2D游桩。因?yàn)閤牲迫,y和z屬性都是Equatable類型,所以接收綜合的等價(jià)運(yùn)營商的實(shí)現(xiàn)众弓。
struct Vector3D: Equatable {
var x = 0.0, y = 0.0, z = 0.0
}
let twoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
let anotherTwoThreeFour = Vector3D(x: 2.0, y: 3.0, z: 4.0)
if twoThreeFour == anotherTwoThreeFour {
print("These two vectors are also equivalent.")
}
自定義運(yùn)算符
除了Swift提供的標(biāo)準(zhǔn)運(yùn)算符之外恩溅,還可以聲明并實(shí)現(xiàn)自己的自定義運(yùn)算符。有關(guān)可用于定義自定義運(yùn)算符的字符列表谓娃,請(qǐng)參閱運(yùn)算符脚乡。
新的運(yùn)算符使用operator關(guān)鍵字全局聲明,并且都標(biāo)有prefix滨达,infix或postfix修飾:
prefix operator +++
上面的示例定義了一個(gè)名為的新前綴運(yùn)算符+++奶稠。此運(yùn)算符在Swift中沒有現(xiàn)有含義,因此在使用Vector2D實(shí)例的特定上下文中給出了它自己的自定義含義捡遍。出于此示例的目的锌订,+++將其視為新的“前綴加倍”運(yùn)算符。它通過使用前面定義的加法賦值運(yùn)算符將向量與自身相加画株,使Vector2D實(shí)例的值x和y值加倍辆飘。為了實(shí)現(xiàn)+++運(yùn)算符,添加一個(gè)名為+++的Vector2D類型方法谓传,如下:
extension Vector2D {
static prefix func +++ (vector: inout Vector2D) -> Vector2D {
vector += vector
return vector
}
}
var toBeDoubled = Vector2D(x: 1.0, y: 4.0)
let afterDoubling = +++toBeDoubled
自定義中綴運(yùn)算符的優(yōu)先級(jí)
自定義中綴運(yùn)算符均需指定優(yōu)先級(jí)組蜈项。優(yōu)先級(jí)組指定運(yùn)算符相對(duì)于其他中綴運(yùn)算符的優(yōu)先級(jí),以及運(yùn)算符的關(guān)聯(lián)性续挟。有關(guān)這些特征如何影響中綴運(yùn)算符與其他中綴運(yùn)算符的交互的說明紧卒,請(qǐng)參閱優(yōu)先級(jí)和關(guān)聯(lián)性。
未明確放入優(yōu)先級(jí)組的自定義中綴運(yùn)算符將被賦予默認(rèn)優(yōu)先級(jí)組诗祸,其優(yōu)先級(jí)即高于三元條件運(yùn)算符的優(yōu)先級(jí)跑芳。
以下示例定義了一個(gè)名為+-的新自定義中綴運(yùn)算符轴总,該運(yùn)算符屬于AdditionPrecedence優(yōu)先級(jí)組:
infix operator +-: AdditionPrecedence
extension Vector2D {
static func +- (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y - right.y)
}
}
let firstVector = Vector2D(x: 1.0, y: 2.0)
let secondVector = Vector2D(x: 3.0, y: 4.0)
let plusMinusVector = firstVector +- secondVector
該運(yùn)算符將兩個(gè)向量的x值相加,并從第一個(gè)向量中減去第二個(gè)向量的y值博个。因?yàn)樗举|(zhì)上是一個(gè)“加法”運(yùn)算符怀樟,所以它被賦予了與加法中綴運(yùn)算符相同的優(yōu)先級(jí)組,例如+和-坡倔。有關(guān)Swift標(biāo)準(zhǔn)庫提供的運(yùn)算符的信息漂佩,包括運(yùn)算符優(yōu)先級(jí)組和關(guān)聯(lián)性設(shè)置的完整列表,請(qǐng)參閱運(yùn)算符聲明罪塔。有關(guān)優(yōu)先級(jí)組的更多信息以及定義自己的運(yùn)算符和優(yōu)先級(jí)組的語法投蝉,請(qǐng)參閱“ 運(yùn)算符聲明”。
注意
定義前綴或后綴運(yùn)算符時(shí)征堪,不指定優(yōu)先級(jí)瘩缆。但是,如果將前綴和后綴運(yùn)算符同時(shí)應(yīng)用于同一操作數(shù)佃蚜,則首先應(yīng)用后綴運(yùn)算符庸娱。