Swift編程二十八(高級(jí)運(yùn)算符)

案例代碼下載

高級(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ù)所有位:


image

按位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:


image

在下面的例子中泳猬,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:


image

在下面的例子中,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:


image

在下面的示例中项秉,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ù)的位移行為如下:

  1. 現(xiàn)有位按所請(qǐng)求的位數(shù)向左或向右移動(dòng)唉侄。
  2. 移除超出整數(shù)存儲(chǔ)邊界的任何位都將被丟棄。
  3. 在原始位向左或向右移動(dòng)之后野建,將零插入到留下的空間中属划。

這種方法被稱為邏輯轉(zhuǎn)換。

下圖顯示了11111111 << 1(11111111按位向左移動(dòng)1)和11111111 >> 1(11111111按位向右移動(dòng)1)的結(jié)果候生。移動(dòng)藍(lán)色數(shù)字同眯,丟棄灰色數(shù)字,并插入橙色零:


image

以下是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ù):


image

符號(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:


image

這一次萌丈,符號(hào)位是1(意思是“負(fù)”),七個(gè)值位的二進(jìn)制值為124(即128 - 4):


image

負(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位猜揪,一旦完成:


image

其次惭墓,二進(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ǔ)位风瘦,而不是零。


image

此操作可確保有符號(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為零讥此。


image

當(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。


image

對(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即可容納的最大正值。


image

對(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)


image

前綴和后綴運(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)算符庸娱。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市谐算,隨后出現(xiàn)的幾起案子熟尉,更是在濱河造成了極大的恐慌,老刑警劉巖洲脂,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斤儿,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡恐锦,警方通過查閱死者的電腦和手機(jī)往果,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來一铅,“玉大人陕贮,你說我怎么就攤上這事∨似” “怎么了肮之?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長卜录。 經(jīng)常有香客問我局骤,道長,這世上最難降的妖魔是什么暴凑? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮赘来,結(jié)果婚禮上现喳,老公的妹妹穿的比我還像新娘凯傲。我一直安慰自己,他們只是感情好嗦篱,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布冰单。 她就那樣靜靜地躺著,像睡著了一般灸促。 火紅的嫁衣襯著肌膚如雪诫欠。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天浴栽,我揣著相機(jī)與錄音荒叼,去河邊找鬼。 笑死典鸡,一個(gè)胖子當(dāng)著我的面吹牛被廓,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播萝玷,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼嫁乘,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了球碉?” 一聲冷哼從身側(cè)響起蜓斧,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎睁冬,沒想到半個(gè)月后挎春,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡痴突,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年搂蜓,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辽装。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡侥猬,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出恭理,到底是詐尸還是另有隱情植影,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布拓巧,位于F島的核電站斯碌,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏肛度。R本人自食惡果不足惜傻唾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧冠骄,春花似錦伪煤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至扁誓,卻和暖如春防泵,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝗敢。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來泰國打工捷泞, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人前普。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓肚邢,卻偏偏與公主長得像,于是被迫代替她去往敵國和親拭卿。 傳聞我的和親對(duì)象是個(gè)殘疾皇子骡湖,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 本章將會(huì)介紹 模塊和源文件訪問級(jí)別訪問控制語法自定義類型子類常量响蕴、變量、屬性惠桃、下標(biāo)構(gòu)造器協(xié)議擴(kuò)展泛型類型別名位運(yùn)算...
    寒橋閱讀 884評(píng)論 0 2
  • 高級(jí)運(yùn)算符 文檔地址 作為 基本運(yùn)算符 的補(bǔ)充浦夷,Swift 提供了幾個(gè)高級(jí)運(yùn)算符執(zhí)行對(duì)數(shù)傳值進(jìn)行更加復(fù)雜的操作。這...
    hrscy閱讀 842評(píng)論 0 2
  • 除了基本運(yùn)算符,Swift 中還有許多可以對(duì)數(shù)值進(jìn)行復(fù)雜運(yùn)算的高級(jí)運(yùn)算符辜王。這些高級(jí)運(yùn)算符包含了在位運(yùn)算符和移位運(yùn)算...
    答案MK閱讀 679評(píng)論 0 2
  • 中文文檔 一劈狐、位運(yùn)算符 位操作符通常在諸如圖像處理和創(chuàng)建設(shè)備驅(qū)動(dòng)等底層開發(fā)中使用,使用它可以單獨(dú)操作數(shù)據(jù)結(jié)構(gòu)中原始...
    伯wen閱讀 1,490評(píng)論 0 2