Swift基礎(chǔ)語法(十四)高級(jí)運(yùn)算符

Swift基礎(chǔ)學(xué)習(xí)文章匯總

Swift提供了對(duì)運(yùn)算符的特殊操作,本文主要介紹溢出運(yùn)算符、運(yùn)算符重載、自定義運(yùn)算符。

主要內(nèi)容:

  1. 溢出運(yùn)算符
  2. 運(yùn)算符重載
  3. 常見運(yùn)算符協(xié)議
  4. 自定義運(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ì):

溢出運(yùn)算符本質(zhì).png

  • 可以看到在二進(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
}

說明:

  1. 定義前綴運(yùn)算符符號(hào)為+++
  2. 定義中綴運(yùn)算符+-,且提供了優(yōu)先級(jí)組
  3. 創(chuàng)建優(yōu)先級(jí)組PlusMinusPrecedence
  4. 優(yōu)先級(jí)組中的結(jié)合性為無,不能三個(gè)數(shù)同時(shí)計(jì)算
  5. 這里的高優(yōu)先級(jí)或低優(yōu)先級(jí)不是隨便寫的,而是Apple文檔提供的,需要在運(yùn)算符官方文檔查找
  6. assignment為true表示在可選鏈中它的優(yōu)先級(jí)和賦值運(yùn)算符一樣
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容