// 語(yǔ)法最后一章了老鐵~~~
// 個(gè)人認(rèn)為: 高級(jí)運(yùn)算符也是容易出錯(cuò)的地方
//“Swift 中的算術(shù)運(yùn)算符默認(rèn)是不會(huì)溢出的。所有溢出行為都會(huì)被捕獲并報(bào)告為錯(cuò)誤。如果想讓系統(tǒng)允許溢出行為玛追,可以選擇使用 Swift 中另一套默認(rèn)支持溢出的運(yùn)算符弹渔,比如溢出加法運(yùn)算符(&+)。所有的這些溢出運(yùn)算符都是以 & 開頭的花沉∮嫒拢”
//1. 位運(yùn)算符
//“位運(yùn)算符可以操作數(shù)據(jù)結(jié)構(gòu)中每個(gè)獨(dú)立的 比特位 进鸠。它們通常被用在底層開發(fā)中,比如圖形編程和創(chuàng)建設(shè)備驅(qū)動(dòng)形病。位運(yùn)算符在處理外部資源的原始數(shù)據(jù)時(shí)也十分有用客年,比如對(duì)自定義通信協(xié)議傳輸?shù)臄?shù)據(jù)進(jìn)行編碼和解碼∧牵”
//“Swift 支持 C 語(yǔ)言中的全部位運(yùn)算符”
//1.1 “按位取反運(yùn)算符”
//“按位取反運(yùn)算符(~)可以對(duì)一個(gè)數(shù)值的全部比特位進(jìn)行取反,“按位取反運(yùn)算符是一個(gè)前綴運(yùn)算符量瓜,需要直接放在運(yùn)算的數(shù)之前,并且它們之間不能添加任何空格”
//1.2 按位與運(yùn)算符
//“按位與運(yùn)算符(&)可以對(duì)兩個(gè)數(shù)的比特位進(jìn)行合并途乃。它返回一個(gè)新的數(shù)绍傲,只有當(dāng)兩個(gè)數(shù)的對(duì)應(yīng)位都為 1 的時(shí)候,新數(shù)的對(duì)應(yīng)位才為 1”
//1.3“按位或運(yùn)算符”
//“按位或運(yùn)算符(|)可以對(duì)兩個(gè)數(shù)的比特位進(jìn)行比較耍共。它返回一個(gè)新的數(shù)烫饼,只要兩個(gè)數(shù)的對(duì)應(yīng)位中有任意一個(gè)為 1 時(shí),新數(shù)的對(duì)應(yīng)位就為 1:”
//1.4 按位異或運(yùn)算符
//“按位異或運(yùn)算符(^)可以對(duì)兩個(gè)數(shù)的比特位進(jìn)行比較试读。它返回一個(gè)新的數(shù)杠纵,當(dāng)兩個(gè)數(shù)的對(duì)應(yīng)位不相同時(shí),新數(shù)的對(duì)應(yīng)位就為 1:”
//1.5 “按位左移鹏往、右移運(yùn)算符”
//“按位左移運(yùn)算符(<<)和按位右移運(yùn)算符(>>)可以對(duì)一個(gè)數(shù)的所有位進(jìn)行指定位數(shù)的左移和右移”
//“將一個(gè)整數(shù)左移一位淡诗,等價(jià)于將這個(gè)數(shù)乘以 2骇塘,同樣地伊履,將一個(gè)整數(shù)右移一位,等價(jià)于將這個(gè)數(shù)除以 2款违√破伲”
//2. 溢出運(yùn)算符
//“在默認(rèn)情況下,當(dāng)向一個(gè)整數(shù)賦予超過(guò)它容量的值時(shí)插爹,Swift 默認(rèn)會(huì)報(bào)錯(cuò)哄辣,而不是生成一個(gè)無(wú)效的數(shù)请梢。這個(gè)行為為我們?cè)谶\(yùn)算過(guò)大或著過(guò)小的數(shù)的時(shí)候提供了額外的安全性”
//“也可以選擇讓系統(tǒng)在數(shù)值溢出的時(shí)候采取截?cái)嗵幚恚菆?bào)錯(cuò)力穗∫慊。可以使用 Swift 提供的三個(gè)溢出運(yùn)算符來(lái)讓系統(tǒng)支持整數(shù)溢出運(yùn)算。這些運(yùn)算符都是以 & 開頭的:
/*
溢出加法 &+
溢出減法 &-
溢出乘法 &*”
*/
//2.1 數(shù)值溢出
var unsignedOverFlow = UInt8.max
unsignedOverFlow = unsignedOverFlow &+ 1
//此時(shí)unsignedOverFlow 等于0
var unsignedOverFlowMin = UInt8.min
//“// unsignedOverflow 等于 UInt8 所能容納的最小整數(shù) 0”
unsignedOverFlowMin = unsignedOverFlowMin &- 1
//此時(shí)unsignedOverFlowMin 等于255
//2.2“溢出也會(huì)發(fā)生在有符號(hào)整型數(shù)值上当窗。在對(duì)有符號(hào)整型數(shù)值進(jìn)行溢出加法或溢出減法運(yùn)算時(shí)够坐,符號(hào)位也需要參與計(jì)算”
//“var signedOverflow = Int8.min
// signedOverflow 等于 Int8 所能容納的最小整數(shù) -128
//signedOverflow = signedOverflow &- 1
// 此時(shí) signedOverflow 等于 127”
//3. 優(yōu)先級(jí)與結(jié)合性
//“運(yùn)算符的優(yōu)先級(jí)使得一些運(yùn)算符優(yōu)先于其他運(yùn)算符,高優(yōu)先級(jí)的運(yùn)算符會(huì)先被計(jì)算崖面≡”
//“結(jié)合性定義了相同優(yōu)先級(jí)的運(yùn)算符是如何結(jié)合的,也就是說(shuō)巫员,是與左邊結(jié)合為一組庶香,還是與右邊結(jié)合為一組〖蚴叮可以將這意思理解為“它們是與左邊的表達(dá)式結(jié)合的”或者“它們是與右邊的表達(dá)式結(jié)合的赶掖。
//4.運(yùn)算符函數(shù)
// “類和結(jié)構(gòu)體可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn),這通常被稱為運(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)
}
}
//“例子中定義了一個(gè)名為 Vector2D 的結(jié)構(gòu)體用來(lái)表示二維坐標(biāo)向量 (x, y),緊接著定義了一個(gè)可以對(duì)兩個(gè) Vector2D 結(jié)構(gòu)體進(jìn)行相加的運(yùn)算符函數(shù)”
//“該運(yùn)算符函數(shù)被定義為 Vector2D 上的一個(gè)類方法戳寸,并且函數(shù)的名字與它要進(jìn)行重載的 + 名字一致呈驶。因?yàn)榧臃ㄟ\(yùn)算并不是一個(gè)向量必需的功能,所以這個(gè)類方法被定義在 Vector2D 的一個(gè)擴(kuò)展中疫鹊,而不是 Vector2D 結(jié)構(gòu)體聲明內(nèi)袖瞻。”
//4.1前綴和后綴運(yùn)算符
//“要實(shí)現(xiàn)前綴或者后綴運(yùn)算符拆吆,需要在聲明運(yùn)算符函數(shù)的時(shí)候在 func 關(guān)鍵字之前指定 prefix 或者 postfix 修飾符:”
extension Vector2D {
static prefix func -(vector:Vector2D)->Vector2D{
return Vector2D(x:-vector.x,y:-vector.y)
}
}
//“這段代碼為 Vector2D 類型實(shí)現(xiàn)了單目負(fù)號(hào)運(yùn)算符聋迎。由于該運(yùn)算符是前綴運(yùn)算符,所以這個(gè)函數(shù)需要加上 prefix 修飾符枣耀∶乖危”
//“對(duì)于簡(jiǎn)單數(shù)值,單目負(fù)號(hào)運(yùn)算符可以對(duì)它們的正負(fù)性進(jìn)行改變捞奕。對(duì)于 Vector2D 來(lái)說(shuō)牺堰,該運(yùn)算將其 x 和 y 屬性的正負(fù)性都進(jìn)行了改變”
let positive = Vector2D(x:3.0,y:4.0)
let negative = -positive
//“ negative 是一個(gè)值為 (-3.0, -4.0) 的 Vector2D 實(shí)例”
//4.2 復(fù)合賦值運(yùn)算符
//“復(fù)合賦值運(yùn)算符將賦值運(yùn)算符(=)與其它運(yùn)算符進(jìn)行結(jié)合。例如颅围,將加法與賦值結(jié)合成加法賦值運(yùn)算符(+=)伟葫。在實(shí)現(xiàn)的時(shí)候,需要把運(yùn)算符的左參數(shù)設(shè)置成 inout 類型院促,因?yàn)檫@個(gè)參數(shù)的值會(huì)在運(yùn)算符函數(shù)內(nèi)直接被修改筏养「В”
//“不能對(duì)默認(rèn)的賦值運(yùn)算符(=)進(jìn)行重載。只有組合賦值運(yùn)算符可以被重載渐溶。同樣地辉浦,也無(wú)法對(duì)三目條件運(yùn)算符 (a ? b : c) 進(jìn)行重載【シ”
//4.3 等價(jià)運(yùn)算符
// “自定義的類和結(jié)構(gòu)體沒(méi)有對(duì)等價(jià)運(yùn)算符進(jìn)行默認(rèn)實(shí)現(xiàn)盏浙,等價(jià)運(yùn)算符通常被稱為“相等”運(yùn)算符(==)與“不等”運(yùn)算符(!=)。對(duì)于自定義類型荔茬,Swift 無(wú)法判斷其是否“相等”废膘,因?yàn)椤跋嗟取钡暮x取決于這些自定義類型在你的代碼中所扮演的角色∧轿担”
//“為了使用等價(jià)運(yùn)算符能對(duì)自定義的類型進(jìn)行判等運(yùn)算丐黄,需要為其提供自定義實(shí)現(xiàn),實(shí)現(xiàn)的方法與其它中綴運(yùn)算符一樣:”
extension Vector2D {
static func == (left: Vector2D, right: Vector2D) -> Bool {
return (left.x == right.x) && (left.y == right.y)
}
static func != (left: Vector2D, right: Vector2D) -> Bool {
return !(left == right)
}
}
//“上述代碼實(shí)現(xiàn)了“相等”運(yùn)算符(==)來(lái)判斷兩個(gè) Vector2D 實(shí)例是否相等孔飒。對(duì)于 Vector2D 類型來(lái)說(shuō)灌闺,“相等”意味著“兩個(gè)實(shí)例的 x 屬性和 y 屬性都相等”,這也是代碼中用來(lái)進(jìn)行判等的邏輯坏瞄。示例里同時(shí)也實(shí)現(xiàn)了“不等”運(yùn)算符(!=)桂对,它簡(jiǎn)單地將“相等”運(yùn)算符的結(jié)果進(jìn)行取反后返回”
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")
}
//5. 自定義運(yùn)算符
//“在 Swift 中還可以聲明和實(shí)現(xiàn)自定義運(yùn)算符”
//“新的運(yùn)算符要使用 operator 關(guān)鍵字在全局作用域內(nèi)進(jìn)行定義,同時(shí)還要指定 prefix鸠匀、infix 或者 postfix 修飾符”
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)”