一辨液、位運(yùn)算符
位操作符通常在諸如圖像處理和創(chuàng)建設(shè)備驅(qū)動(dòng)等底層開發(fā)中使用屡穗,使用它可以單獨(dú)操作數(shù)據(jù)結(jié)構(gòu)中原始數(shù)據(jù)的比特位撤防。在使用一個(gè)自定義的協(xié)議進(jìn)行通信的時(shí)候叙谨,運(yùn)用位運(yùn)算符來對原始數(shù)據(jù)進(jìn)行編碼和解碼也是非常有效的。
1瓤鼻、按位取反運(yùn)算符
-
~
: 按位取反運(yùn)算符, 對一個(gè)操作數(shù)的每一位都取反
- 這個(gè)運(yùn)算符是前置的秉版,所以請不加任何空格地寫著操作數(shù)之前。
let initialBits: UInt8 = 0b00001111
let invertedBits = ~initialBits // 等于 0b11110000
2茬祷、按位與運(yùn)算符
-
&
: 按位與運(yùn)算符對兩個(gè)數(shù)進(jìn)行操作清焕,然后返回一個(gè)新的數(shù),這個(gè)數(shù)的每個(gè)位都需要兩個(gè)輸入數(shù)的同一位都為1
時(shí)才為1
祭犯。
- 以下代碼秸妥,firstSixBits和lastSixBits中間4個(gè)位都為1。對它倆進(jìn)行按位與運(yùn)算后沃粗,就得到了00111100粥惧,即十進(jìn)制的60。
let firstSixBits: UInt8 = 0b11111100
let lastSixBits: UInt8 = 0b00111111
let middleFourBits = firstSixBits & lastSixBits // 等于 00111100
3最盅、按位或運(yùn)算
-
|
: 按位或運(yùn)算符, 比較兩個(gè)數(shù)突雪,然后返回一個(gè)新的數(shù),這個(gè)數(shù)的每一位設(shè)置1
的條件是兩個(gè)輸入數(shù)的同一位都不為0
(即任意一個(gè)為1
涡贱,或都為1
)咏删。
- 如下代碼,someBits和moreBits在不同位上有1问词。按位或運(yùn)行的結(jié)果是11111110督函,即十進(jìn)制的254。
let someBits: UInt8 = 0b10110010
let moreBits: UInt8 = 0b01011110
let combinedbits = someBits | moreBits // 等于 11111110
4、按位異或運(yùn)算符
-
^
: 按位異或運(yùn)算符, 比較兩個(gè)數(shù)辰狡,然后返回一個(gè)數(shù)锋叨,這個(gè)數(shù)的每個(gè)位設(shè)為1的條件是兩個(gè)輸入數(shù)的同一位不同,如果相同就設(shè)為0搓译。
- 以下代碼悲柱,firstBits和otherBits都有一個(gè)1跟另一個(gè)數(shù)不同的。所以按位異或的結(jié)果是把它這些位置為1些己,其他都置為0豌鸡。
let firstBits: UInt8 = 0b00010100
let otherBits: UInt8 = 0b00000101
let outputBits = firstBits ^ otherBits // 等于 00010001
5、按位左移/右移運(yùn)算符
左移運(yùn)算符
<<
和右移運(yùn)算符>>
會(huì)把一個(gè)數(shù)的所有比特位按以下定義的規(guī)則向左或向右移動(dòng)指定位數(shù)段标。按位左移和按位右移的效果相當(dāng)把一個(gè)整數(shù)乘于或除于一個(gè)因子為2的整數(shù)涯冠。向左移動(dòng)一個(gè)整型的比特位相當(dāng)于把這個(gè)數(shù)
乘于2
,向右移一位就是除于2
逼庞。
6蛇更、無符整型的移位操作
- 對無符整型的移位的效果如下:
已經(jīng)存在的比特位向左或向右移動(dòng)指定的位數(shù)。
被移出整型存儲(chǔ)邊界的的位數(shù)直接拋棄赛糟,移動(dòng)留下的空白位用零0來填充派任。這種方法稱為邏輯移位。
- 以下這張把展示了 11111111 << 1(11111111向左移1位)璧南,和 11111111 >> 1(11111111向右移1位)掌逛。藍(lán)色的是被移位的,灰色是被拋棄的司倚,橙色的0是被填充進(jìn)來的
let shiftBits: UInt8 = 4 // 即二進(jìn)制的00000100
shiftBits << 1 // 00001000
shiftBits << 2 // 00010000
shiftBits << 5 // 10000000
shiftBits << 6 // 00000000
shiftBits >> 2 // 00000001
- 你可以使用移位操作進(jìn)行其他數(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è)例子使用了一個(gè)UInt32的命名為pink的常量來存儲(chǔ)層疊樣式表CSS中粉色的顏色值,CSS顏色#CC6699在Swift用十六進(jìn)制0xCC6699來表示动知。然后使用按位與(&)和按位右移就可以從這個(gè)顏色值中解析出紅(CC)皿伺,綠(66),藍(lán)(99)三個(gè)部分盒粮。
對0xCC6699和0xFF0000進(jìn)行按位與&操作就可以得到紅色部分鸵鸥。0xFF0000中的0了遮蓋了OxCC6699的第二和第三個(gè)字節(jié),這樣6699被忽略了丹皱,只留下0xCC0000妒穴。
然后,按向右移動(dòng)16位种呐,即 >> 16宰翅。十六進(jìn)制中每兩個(gè)字符是8比特位弃甥,所以移動(dòng)16位的結(jié)果是把0xCC0000變成0x0000CC爽室。這和0xCC是相等的,都是十進(jìn)制的204。
同樣的阔墩,綠色部分來自于0xCC6699和0x00FF00的按位操作得到0x006600嘿架。然后向右移動(dòng)8們,得到0x66啸箫,即十進(jìn)制的102耸彪。
最后,藍(lán)色部分對0xCC6699和0x0000FF進(jìn)行按位與運(yùn)算忘苛,得到0x000099蝉娜,無需向右移位了,所以結(jié)果就是0x99扎唾,即十進(jìn)制的153召川。
7、有符整型的移位操作
- 有符整型的移位操作相對復(fù)雜得多胸遇,因?yàn)檎?fù)號(hào)也是用二進(jìn)制位表示的
- 有符整型通過第1個(gè)比特位(稱為符號(hào)位)來表達(dá)這個(gè)整數(shù)是正數(shù)還是負(fù)數(shù)荧呐。0代表正數(shù),1代表負(fù)數(shù)纸镊。
- 其余的比特位(稱為數(shù)值位)存儲(chǔ)其實(shí)值倍阐。有符正整數(shù)和無符正整數(shù)在計(jì)算機(jī)里的存儲(chǔ)結(jié)果是一樣的,下來我們來看+4內(nèi)部的二進(jìn)制結(jié)構(gòu)逗威。
- 符號(hào)位為0峰搪,代表正數(shù),另外7比特位二進(jìn)制表示的實(shí)際值就剛好是4庵楷。
- 負(fù)數(shù)呢罢艾,跟正數(shù)不同。負(fù)數(shù)存儲(chǔ)的是
2
的n
次方減去它的絕對值尽纽,n為數(shù)值位的位數(shù)咐蚯。一個(gè)8
比特的數(shù)有7
個(gè)數(shù)值位,所以是2
的7
次方弄贿,即128
春锋。 - 我們來看-4存儲(chǔ)的二進(jìn)制結(jié)構(gòu)。
- 現(xiàn)在符號(hào)位為
1
差凹,代表負(fù)數(shù)期奔,7
個(gè)數(shù)值位要表達(dá)的二進(jìn)制值是124
社裆,即128 - 4
碰纬。
負(fù)數(shù)的編碼方式稱為二進(jìn)制補(bǔ)碼表示。這種表示方式看起來很奇怪错沽,但它有幾個(gè)優(yōu)點(diǎn)谊娇。
首先肺孤,只需要對全部8個(gè)比特位(包括符號(hào))做標(biāo)準(zhǔn)的二進(jìn)制加法就可以完成 -1 + -4 的操作,忽略加法過程產(chǎn)生的超過8個(gè)比特位表達(dá)的任何信息。
- 第二赠堵,由于使用二進(jìn)制補(bǔ)碼表示小渊,我們可以和正數(shù)一樣對負(fù)數(shù)進(jìn)行按位左移右移的,同樣也是左移1位時(shí)乘于2茫叭,右移1位時(shí)除于2酬屉。要達(dá)到此目的,對有符整型的右移有一個(gè)特別的要求:
對有符整型按位右移時(shí)揍愁,使用符號(hào)位(正數(shù)為0呐萨,負(fù)數(shù)為1)填充空白位。
這就確保了在右移的過程中莽囤,有符整型的符號(hào)不會(huì)發(fā)生變化垛吗。這稱為算術(shù)移位。
正因?yàn)檎龜?shù)和負(fù)數(shù)特殊的存儲(chǔ)方式烁登,向右移位使它接近于0怯屉。移位過程中保持符號(hào)會(huì)不變,負(fù)數(shù)在接近0的過程中一直是負(fù)數(shù)饵沧。
二锨络、溢出運(yùn)算符
- 默認(rèn)情況下,當(dāng)你往一個(gè)整型常量或變量賦于一個(gè)它不能承載的大數(shù)時(shí)狼牺,Swift不會(huì)讓你這么干的羡儿,它會(huì)報(bào)錯(cuò)。這樣是钥,在操作過大或過小的數(shù)的時(shí)候就很安全了掠归。
var potentialOverflow = Int16.max
// potentialOverflow 等于 32767, 這是 Int16 能承載的最大整數(shù)
potentialOverflow += 1
// 噢, 出錯(cuò)了
- 當(dāng)然,你有意在溢出時(shí)對有效位進(jìn)行截?cái)嗲哪啵憧刹捎靡绯鲞\(yùn)算虏冻,而非錯(cuò)誤處理。Swfit為整型計(jì)算提供了5個(gè)&符號(hào)開頭的溢出運(yùn)算符弹囚。
溢出加法 &+
溢出減法 &-
溢出乘法 &*
溢出除法 &/
溢出求余 &%
1厨相、值的上溢出
- 下面例子使用了溢出加法
&+
來解剖的無符整數(shù)的上溢出
var willOverflow = UInt8.max
// willOverflow 等于UInt8的最大整數(shù) 255
willOverflow = willOverflow &+ 1
// 這時(shí)候 willOverflow 等于 0
- willOverflow用Int8所能承載的最大值255(二進(jìn)制11111111),然后用&+加1鸥鹉。然后UInt8就無法表達(dá)這個(gè)新值的二進(jìn)制了蛮穿,也就導(dǎo)致了這個(gè)新值上溢出了,大家可以看下圖毁渗。溢出后践磅,新值在UInt8的承載范圍內(nèi)的那部分是00000000,也就是0灸异。
2府适、值的下溢出
- 數(shù)值也有可能因?yàn)樘《浇缁眉睢Ee個(gè)例子:
- UInt8的最小值是0(二進(jìn)制為00000000)。使用
&-
進(jìn)行溢出減1细溅,就會(huì)得到二進(jìn)制的11111111即十進(jìn)制的255。
- Swift代碼是這樣的:
var willUnderflow = UInt8.min
// willUnderflow 等于UInt8的最小值0
willUnderflow = willUnderflow &- 1
// 此時(shí) willUnderflow 等于 255
- 有符整型也有類似的下溢出儡嘶,有符整型所有的減法也都是對包括在符號(hào)位在內(nèi)的二進(jìn)制數(shù)進(jìn)行二進(jìn)制減法的喇聊,這在 "按位左移/右移運(yùn)算符" 一節(jié)提到過。最小的有符整數(shù)是-128蹦狂,即二進(jìn)制的10000000誓篱。用溢出減法減去去1后,變成了01111111凯楔,即UInt8所能承載的最大整數(shù)127窜骄。
- 對應(yīng)Swift代碼
var signedUnderflow = Int8.min
// signedUnderflow 等于最小的有符整數(shù) -128
signedUnderflow = signedUnderflow &- 1
// 如今 signedUnderflow 等于 127
3、除零溢出
- 一個(gè)數(shù)除于0
i / 0
摆屯,或者對0求余數(shù)i % 0
邻遏,就會(huì)產(chǎn)生一個(gè)錯(cuò)誤。
let x = 1
let y = x / 0
- 使用它們對應(yīng)的可溢出的版本的運(yùn)算符
&/
和&%
進(jìn)行除0操作時(shí)就會(huì)得到0值虐骑。
let x = 1
let y = x &/ 0
// y 等于 0
三准验、優(yōu)先級(jí)和結(jié)合性
- 與數(shù)學(xué)中的優(yōu)先級(jí)和結(jié)合性相同
四、運(yùn)算符函數(shù)
讓已有的運(yùn)算符也可以對自定義的類和結(jié)構(gòu)進(jìn)行運(yùn)算廷没,這稱為運(yùn)算符重載糊饱。
例子中定義了一個(gè)名為Vector2D的二維坐標(biāo)向量 (x,y) 的結(jié)構(gòu)颠黎,然后定義了讓兩個(gè)Vector2D的對象相加的運(yùn)算符函數(shù)另锋。
struct Vector2D {
var x = 0.0, y = 0.0
}
func + (left: Vector2D, right: Vector2D) -> Vector2D {
return Vector2D(x: left.x + right.x, y: left.y + right.y)
}
在這個(gè)代碼實(shí)現(xiàn)中,參數(shù)被命名為了left和right狭归,代表+左邊和右邊的兩個(gè)Vector2D對象夭坪。函數(shù)返回了一個(gè)新的Vector2D的對象,這個(gè)對象的x和y分別等于兩個(gè)參數(shù)對象的x和y的和过椎。
這個(gè)函數(shù)是全局的台舱,而不是Vector2D結(jié)構(gòu)的成員方法,所以任意兩個(gè)Vector2D對象都可以使用這個(gè)中置運(yùn)算符潭流。
let v1 = Vector2D(x: 1, y: 2)
let v2 = Vector2D(x: 3, y: 4)
print(v1 + v2) // 打印: Vector2D(x: 4.0, y: 6.0)
2竞惋、前置和后置運(yùn)算符
上個(gè)例子演示了一個(gè)雙目中置運(yùn)算符的自定義實(shí)現(xiàn),同樣我們也可以玩標(biāo)準(zhǔn)單目運(yùn)算符的實(shí)現(xiàn)灰嫉。單目運(yùn)算符只有一個(gè)操作數(shù)拆宛,在操作數(shù)之前就是前置的,如-a; 在操作數(shù)之后就是后置的讼撒,如i++浑厚。
實(shí)現(xiàn)一個(gè)前置或后置運(yùn)算符時(shí)股耽,在定義該運(yùn)算符的時(shí)候于關(guān)鍵字func之前標(biāo)注
prefix
或postfix
屬性。下面實(shí)現(xiàn)
-
取反運(yùn)算符
prefix func - (vector: Vector2D) -> Vector2D {
return Vector2D(x: -vector.x, y: -vector.y)
}
- 調(diào)用
print(-v1) // 打印: Vector2D(x: -1.0, y: -2.0)
3钳幅、組合賦值運(yùn)算符
- 組合賦值是其他運(yùn)算符和賦值運(yùn)算符一起執(zhí)行的運(yùn)算物蝙。如+=把加運(yùn)算和賦值運(yùn)算組合成一個(gè)操作
func += (inout left: Vector2D, right: Vector2D) {
left = left + right
}
- 因?yàn)榧臃ㄟ\(yùn)算在之前定義過了,這里無需重新定義敢艰。所以诬乞,加賦運(yùn)算符函數(shù)使用已經(jīng)存在的高級(jí)加法運(yùn)算符函數(shù)來執(zhí)行左值加右值的運(yùn)算。
var a = Vector2D(x: 1.0, y: 2.0)
let b = Vector2D(x: 3.0, y: 4.0)
a += b
// a 現(xiàn)在為 (4.0, 6.0)
注意:默認(rèn)的賦值符(
=
)是不可重載的钠导。只有組合賦值符可以重載震嫉。三目條件運(yùn)算符 (a ? b : c
) 也是不可重載。
4牡属、等價(jià)運(yùn)算符
定義的類和結(jié)構(gòu)體沒有對等價(jià)運(yùn)算符進(jìn)行默認(rèn)實(shí)現(xiàn)票堵,等價(jià)運(yùn)算符通常被稱為“相等”運(yùn)算符(
==
)與“不等”運(yùn)算符(!=
)。對于自定義類型逮栅,Swift 無法判斷其是否“相等”悴势,因?yàn)椤跋嗟取钡暮x取決于這些自定義類型在你的代碼中所扮演的角色。為了使用等價(jià)運(yùn)算符能對自定義的類型進(jìn)行判等運(yùn)算措伐,需要為其提供自定義實(shí)現(xiàn)瞳浦,實(shí)現(xiàn)的方法與其它中綴運(yùn)算符一樣, 并且增加對標(biāo)準(zhǔn)庫
Equatable
協(xié)議的遵循:
extension Vector2D: Equatable {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
}
- 上述代碼實(shí)現(xiàn)了“相等”運(yùn)算符(
==
)來判斷兩個(gè) Vector2D 實(shí)例是否相等。對于 Vector2D 類型來說废士,“相等”意味著“兩個(gè)實(shí)例的 x 屬性和 y 屬性都相等”叫潦,這也是代碼中用來進(jìn)行判等的邏輯。
示例里同時(shí)也實(shí)現(xiàn)了“不等”運(yùn)算符(
!=
)官硝,它簡單地將“相等”運(yùn)算符的結(jié)果進(jìn)行取反后返回矗蕊。
- 現(xiàn)在我們可以使用這兩個(gè)運(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.")
}
// 打印 “These two vectors are equivalent.”
- Swift 為以下自定義類型提等價(jià)運(yùn)算符供合成實(shí)現(xiàn):
只擁有遵循 Equatable 協(xié)議存儲(chǔ)屬性的結(jié)構(gòu)體;
只擁有遵循 Equatable 協(xié)議關(guān)聯(lián)類型的枚舉氢架;
沒有關(guān)聯(lián)類型的枚舉傻咖。
在類型原本的聲明中聲明遵循
Equatable
來接收這些默認(rèn)實(shí)現(xiàn)。下面為三維位置向量
(x, y, z)
定義的Vector3D
結(jié)構(gòu)體岖研,與Vector2D
類似卿操,由于x
,y
和z
屬性都是Equatable
類型孙援,Vector3D
就收到默認(rèn)的等價(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.")
}
// Prints "These two vectors are also equivalent."
五、自定義運(yùn)算符
- Swift 中還可以聲明和實(shí)現(xiàn)自定義運(yùn)算符拓售。
注意
以下這些標(biāo)記=
窥摄、->
、//
础淤、/*
崭放、*/
哨苛、.
、<
(前綴運(yùn)算符)币砂、&
建峭、?
、?
(中綴運(yùn)算符)决摧、>
(后綴運(yùn)算符)亿蒸、!
、?
是被系統(tǒng)保留的蜜徽。這些符號(hào)不能被重載,也不能用于自定義運(yùn)算符票摇。
- 新的運(yùn)算符要使用
operator
關(guān)鍵字在全局作用域內(nèi)進(jìn)行定義拘鞋,同時(shí)還要指定prefix
、infix
或者postfix
修飾符:
prefix: 前置運(yùn)算符
infix: 中置運(yùn)算符
postfix: 后置運(yùn)算符
prefix operator +++
- 上面的代碼定義了一個(gè)新的名為
+++
的前綴運(yùn)算符矢门。對于這個(gè)運(yùn)算符盆色,在 Swift 中并沒有意義,因此我們針對Vector2D
的實(shí)例來定義它的意義祟剔。
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
// toBeDoubled 現(xiàn)在的值為 (2.0, 8.0)
// afterDoubling 現(xiàn)在的值也為 (2.0, 8.0)
1隔躲、自定義中綴運(yùn)算符的優(yōu)先級(jí)
每個(gè)自定義中綴運(yùn)算符都屬于某個(gè)優(yōu)先級(jí)組。這個(gè)優(yōu)先級(jí)組指定了這個(gè)運(yùn)算符和其他中綴運(yùn)算符的優(yōu)先級(jí)和結(jié)合性物延。
而沒有明確放入優(yōu)先級(jí)組的自定義中綴運(yùn)算符會(huì)放到一個(gè)默認(rèn)的優(yōu)先級(jí)組內(nèi)宣旱,其優(yōu)先級(jí)高于三元運(yùn)算符。
以下例子定義了一個(gè)新的自定義中綴運(yùn)算符 +-叛薯,此運(yùn)算符屬于 AdditionPrecedence 優(yōu)先組:
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
// plusMinusVector 是一個(gè) Vector2D 實(shí)例浑吟,并且它的值為 (4.0, -2.0)
2、定義優(yōu)先級(jí)別名
- 可以使用下面的方式, 自定義操作符的優(yōu)先級(jí), 這依賴于已有優(yōu)先級(jí), 比如下面的
AdditionPrecedence
和MultiplicationPrecedence
// >>>操作符, 優(yōu)先級(jí)別名
infix operator >>> : ATPrecedence
precedencegroup ATPrecedence { //定義運(yùn)算符優(yōu)先級(jí)ATPrecedence
associativity: left
higherThan: AdditionPrecedence
lowerThan: MultiplicationPrecedence
}
- 直接指定操作符的類型耗溜,對這個(gè)類型進(jìn)行定義
associativity: left 表示左結(jié)合
higherThan 優(yōu)先級(jí)高于 AdditionPrecedence 這個(gè)是加法的類型
lowerThan 優(yōu)先級(jí)低于 MultiplicationPrecedence 乘除
- 這里給出常用類型對應(yīng)的group
infix operator || : LogicalDisjunctionPrecedence
infix operator && : LogicalConjunctionPrecedence
infix operator < : ComparisonPrecedence
infix operator <= : ComparisonPrecedence
infix operator > : ComparisonPrecedence
infix operator >= : ComparisonPrecedence
infix operator == : ComparisonPrecedence
infix operator != : ComparisonPrecedence
infix operator === : ComparisonPrecedence
infix operator !== : ComparisonPrecedence
infix operator ~= : ComparisonPrecedence
infix operator ?? : NilCoalescingPrecedence
infix operator + : AdditionPrecedence
infix operator - : AdditionPrecedence
infix operator &+ : AdditionPrecedence
infix operator &- : AdditionPrecedence
infix operator | : AdditionPrecedence
infix operator ^ : AdditionPrecedence
infix operator * : MultiplicationPrecedence
infix operator / : MultiplicationPrecedence
infix operator % : MultiplicationPrecedence
infix operator &* : MultiplicationPrecedence
infix operator & : MultiplicationPrecedence
infix operator << : BitwiseShiftPrecedence
infix operator >> : BitwiseShiftPrecedence
infix operator ..< : RangeFormationPrecedence
infix operator ... : RangeFormationPrecedence
infix operator *= : AssignmentPrecedence
infix operator /= : AssignmentPrecedence
infix operator %= : AssignmentPrecedence
infix operator += : AssignmentPrecedence
infix operator -= : AssignmentPrecedence
infix operator <<= : AssignmentPrecedence
infix operator >>= : AssignmentPrecedence
infix operator &= : AssignmentPrecedence
infix operator ^= : AssignmentPrecedence
infix operator |= : AssignmentPrecedence