Swift提供了對(duì)運(yùn)算符的特殊操作,本文主要介紹溢出運(yùn)算符、運(yùn)算符重載、自定義運(yùn)算符。
主要內(nèi)容:
- 溢出運(yùn)算符
- 運(yùn)算符重載
- 常見運(yùn)算符協(xié)議
- 自定義運(yùn)算符
1. 溢出運(yùn)算符
算數(shù)運(yùn)算符中出現(xiàn)溢出時(shí)會(huì)拋出運(yùn)行時(shí)錯(cuò)誤,因此Swift提供了溢出運(yùn)算符(&+,&-,&*),支持溢出運(yùn)算,即使溢出也會(huì)正常計(jì)算而不是錯(cuò)誤
代碼:
/*
1、溢出運(yùn)算符
*/
var min = UInt8.min
print(min &- 1) // 255, Int8.max
var max = UInt8.max
print(max &+ 1) // 0, Int8.min
print(max &* 2) // 254, 等價(jià)于 max &+ max
說明:
1、加減乘三種才可以,除法是不行的(自己后面寫博客的時(shí)候驗(yàn)證下)
2、溢出時(shí)數(shù)值是頭尾相連來判斷的,比如255 &+ 2 = 1。
3、可以通過取余計(jì)算,以溢出加法來看,上面的應(yīng)該等價(jià)于(255+2)%256 = 1
本質(zhì):

- 可以看到在二進(jìn)制上的計(jì)算其實(shí)是正常的計(jì)算方式
- 本質(zhì)上依然是正常的加減乘,只不過計(jì)算后不會(huì)報(bào)錯(cuò)。如果是正常的加法,255+1,就會(huì)進(jìn)位,此時(shí)后面的8位全為0,而進(jìn)位的1不會(huì)報(bào)錯(cuò)。
2. 運(yùn)算符重載
類、結(jié)構(gòu)體、枚舉可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn),這個(gè)操作就叫做運(yùn)算符重載
代碼:
/*
2、運(yùn)算符重載
*/
struct Point {
var x: Int, y: Int
static func + (p1: Point, p2: Point) -> Point {
Point(x: p1.x + p2.x, y: p1.y + p2.y)
}
static func - (p1: Point, p2: Point) -> Point {
Point(x: p1.x - p2.x, y: p1.y - p2.y)
}
static prefix func - (p: Point) -> Point {
Point(x: -p.x, y: -p.y)
}
static func += (p1: inout Point, p2: Point) {
p1 = p1 + p2
}
static prefix func ++ (p: inout Point) -> Point {
p += Point(x: 1, y: 1)
return p
}
static postfix func ++ (p: inout Point) -> Point {
let tmp = p
p += Point(x: 1, y: 1)
return tmp
}
static func == (p1: Point, p2: Point) -> Bool {
(p1.x == p2.x) && (p1.y == p2.y)
}
}
let point1 = Point(x: 1, y: 1)
let point2 = Point(x: 1, y: 1)
print(point1 + point2)//Point(x: 2, y: 2)
print(point1 == point2)//true
說明:
- 寫到類型內(nèi),必須需要使用static/class,因?yàn)檫@個(gè)運(yùn)算符是跟類型相關(guān)的,而非對(duì)象相關(guān)的,所以使用static
- 簡(jiǎn)單看下寫法就好了
- 重載的運(yùn)算符只需要看自己重載了什么功能,沒有重載的地方仍然和原本的運(yùn)算符的使用一模一樣,在使用上不要有顧慮
3. 常見運(yùn)算符協(xié)議
3.1 Equatable
代碼:
/*
Equatable協(xié)議
*/
struct Point : Equatable {
var x: Int, y: Int
}
var p1 = Point(x: 10, y: 20)
var p2 = Point(x: 11, y: 22)
print(p1 == p2) // false
print(p1 != p2) // true
class Person : Equatable {
var age: Int
init(age: Int) {
self.age = age
}
static func == (lhs: Person, rhs: Person) -> Bool {
lhs.age == rhs.age
}
}
var p1 = Person(age: 10)
var p2 = Person(age: 11)
print(p1 == p2)//false
print(p1 != p2)//true
說明:
1、其實(shí)可以不用寫Equatable,但是一般要寫
2、這個(gè)==重載運(yùn)算符就是Equatable定義的方法
3、Equatable會(huì)幫我們重載!= 運(yùn)算符
4、結(jié)構(gòu)體系統(tǒng)會(huì)自行判斷比較規(guī)則,因此系統(tǒng)會(huì)幫我們比較,Person類需要我們自己比較
默認(rèn)的Equatable實(shí)現(xiàn):
Swift為某些類型默認(rèn)提供了Equatable實(shí)現(xiàn),其本質(zhì)就是有約定俗成的比較規(guī)則系統(tǒng)就會(huì)幫我們實(shí)現(xiàn)。如果系統(tǒng)無法自行判斷比較規(guī)則就不會(huì)幫我們實(shí)現(xiàn)。
enum Answer : Equatable {
case wrong(Int)
case right
}
var s1 = Answer.wrong(10)
var s2 = Answer.wrong(20)
print(s1 == s2)
類型:
- 沒有關(guān)聯(lián)類型的枚舉
- 只擁有遵守Equatable協(xié)議關(guān)聯(lián)類型的枚舉(雖然有關(guān)聯(lián)類型,但是這個(gè)關(guān)聯(lián)類型有自己的比較規(guī)則了,所以默認(rèn)會(huì)比較)
- 只擁有遵守Equatable協(xié)議存儲(chǔ)屬性的結(jié)構(gòu)體(結(jié)構(gòu)體的只有存儲(chǔ)屬性,且所有的存儲(chǔ)屬性如果遵守比較協(xié)議,說明有默認(rèn)的比較規(guī)則,這個(gè)結(jié)構(gòu)體也是可以進(jìn)行比較的)
恒等于運(yùn)算符
print(p1 === p2)
- 默認(rèn)兩個(gè)對(duì)象使用== 比較的是兩個(gè)對(duì)象變量存儲(chǔ)的地址值是否相等,但是類中如果重載了 == 運(yùn)算符,那么只能使用===恒等于運(yùn)算符來比較兩個(gè)對(duì)象的內(nèi)存地址是否相等
- 還有!==是恒不等于運(yùn)算符
3.2 Comparable
comparable協(xié)議提供了比較大小的方法,系統(tǒng)提供的類型已經(jīng)默認(rèn)遵守了,如果我們自己的類型想要比較,需要遵守其協(xié)議,并且實(shí)現(xiàn)其運(yùn)算符
//Comparable協(xié)議
struct Student : Comparable {
var age: Int
var score: Int
init(score: Int, age: Int) {
self.score = score
self.age = age
}
static func < (lhs: Student, rhs: Student) -> Bool {
(lhs.score < rhs.score)
|| (lhs.score == rhs.score && lhs.age > rhs.age)
}
static func > (lhs: Student, rhs: Student) -> Bool {
(lhs.score > rhs.score)
|| (lhs.score == rhs.score && lhs.age < rhs.age)
}
static func <= (lhs: Student, rhs: Student) -> Bool {
!(lhs > rhs)
}
static func >= (lhs: Student, rhs: Student) -> Bool {
!(lhs < rhs)
}
}
var stu1 = Student(score: 100, age: 20)
var stu2 = Student(score: 98, age: 18)
var stu3 = Student(score: 100, age: 20)
print(stu1 > stu2) // true
print(stu1 >= stu2) // true
print(stu1 >= stu3) // true
print(stu1 <= stu3) // true
print(stu2 < stu1) // true
print(stu2 <= stu1) // true
4. 自定義運(yùn)算符
可以自定義新的運(yùn)算符實(shí)現(xiàn)自己的運(yùn)算功能
運(yùn)算符類型:
- prefix operator:前綴運(yùn)算符
- postfix operator:后綴運(yùn)算符
- infix operator:中綴運(yùn)算符 : 優(yōu)先級(jí)組
優(yōu)先級(jí)組:
precedencegroup 優(yōu)先級(jí)組 {
associativity: 結(jié)合性(left\right\none)
higherThan: 比誰的優(yōu)先級(jí)高
lowerThan: 比誰的優(yōu)先級(jí)低
assignment: true代表在可選鏈操作中擁有跟賦值運(yùn)算符一樣的優(yōu)先級(jí)
}
實(shí)際案例:
prefix operator +++
infix operator +- : PlusMinusPrecedence
precedencegroup PlusMinusPrecedence {
associativity: none
higherThan: AdditionPrecedence
lowerThan: MultiplicationPrecedence
assignment: true
}
說明:
- 定義前綴運(yùn)算符符號(hào)為+++
- 定義中綴運(yùn)算符+-,且提供了優(yōu)先級(jí)組
- 創(chuàng)建優(yōu)先級(jí)組PlusMinusPrecedence
- 優(yōu)先級(jí)組中的結(jié)合性為無,不能三個(gè)數(shù)同時(shí)計(jì)算
- 這里的高優(yōu)先級(jí)或低優(yōu)先級(jí)不是隨便寫的,而是Apple文檔提供的,需要在運(yùn)算符官方文檔查找
- assignment為true表示在可選鏈中它的優(yōu)先級(jí)和賦值運(yùn)算符一樣