十五乘碑、可選項(xiàng)的本質(zhì)、高級(jí)運(yùn)算符(重載)金拒、擴(kuò)展

可選項(xiàng)的本質(zhì)

可選項(xiàng)的本質(zhì)是enum類型
Wrapped為泛型
var age: Int? = 10
age = 20
age = nil

//結(jié)合枚舉及泛型理解
var age1: Optional<Int> = .some(10)
age1 = .some(20)
age = .none
var age: Int? = 10

var age2: Optional<Int> = Optional<Int>.some(10)//完整寫法
var age3: Optional = .some(10)//通過(guò)10將Optional泛型類型確定
var age4 = Optional.some(10)//枚舉變量賦值
var age5 = Optional(10)//枚舉初始化器

age = nil//語(yǔ)法糖
age2 = .none//顯式
var age6 = Optional<Int>.none//確定泛型類型 所以Int必須寫
var age7 :Optional<Int> = .none

print(age == age2)//輸出:true 就是一樣的 僅寫法不同

因此也可以通過(guò)Switch和if語(yǔ)句進(jìn)行判斷

switch age {
case let age? :
    print(age)
case nil :
    print("nil")
}

switch age {
case let .some(v) :// .some(let v) 都可以
    print(v)
case nil :
    print("nil")
}
多重可選類型
var age: Int? = 10
var age1: Int?? = age
age1 = nil

var age2 = Optional.some(Optional.some(10))
age2 = .none
var age3: Optional<Optional<Int>> = .some(.some(10))
var age4: Optional<Optional> = .some(.some(10))

var age5: Int?? = 10
var age6: Optional<Optional> = 10

高級(jí)運(yùn)算符

溢出運(yùn)算符
  • Swift的算術(shù)運(yùn)算符出現(xiàn)溢出時(shí)會(huì)拋出運(yùn)行時(shí)錯(cuò)誤
  • Swift有溢出運(yùn)算符(&+、&-套腹、&*)绪抛,用來(lái)支持溢出運(yùn)算
var min = UInt8.min //0
//min -= 1//此時(shí)會(huì)運(yùn)行時(shí)錯(cuò)誤
min = min &- 1 //255 UInt8.max

var max = UInt8.max //255
//max += 1//此時(shí)會(huì)運(yùn)行時(shí)錯(cuò)誤
max = max &+ 1 //0 UInt8.min

max = UInt8.max
print(max &* 2)//max+1+254 = 254
溢出運(yùn)算符圖解

運(yùn)算符重載

  • 類、結(jié)構(gòu)體电禀、枚舉可以為現(xiàn)有的運(yùn)算符提供自定義的實(shí)現(xiàn)幢码,即運(yùn)算符重載
struct Point {
    var x: Int ,y: Int
}

func + (_ p1: Point, _ p2: Point) -> Point {
    Point(x: p1.x + p2.x, y: p1.y + p2.y)
}

let p = Point(x: 10, y: 10) + Point(x: 20, y: 20)
print(p)//Point(x: 30, y: 30)

struct Size {
    var width: Int ,height: Int
    //如果需要寫在結(jié)構(gòu)體中 需要加上static
    static func + (_ s1: Size, _ s2: Size) -> Size {
        Size(width: s1.width + s2.width, height: s1.height + s2.height)
    }
}

let s = Size(width: 10, height: 10) + Size(width: 20, height: 20)
print(s)//Size(width: 30, height: 30)
struct Size {
    var width: Int ,height: Int
    //如果需要寫在類、結(jié)構(gòu)體中 需要加上static 因?yàn)檫@不是實(shí)例調(diào)用的函數(shù)
    static func + (_ s1: Size, _ s2: Size) -> Size {
        Size(width: s1.width + s2.width, height: s1.height + s2.height)
    }
    
    static func - (_ s1: Size, _ s2: Size) -> Size {
        Size(width: s1.width - s2.width, height: s1.height - s2.height)
    }
    
    static func += (_ s1: inout Size, _ s2: Size){
        s1 = s1 + s2
    }
    
    static prefix func ++ (_ s1: inout Size) -> Size {//前++運(yùn)算符
        s1 += Size(width: 1, height: 1)
        return s1
    }
    
    static postfix func ++ (_ s1: inout Size) -> Size {//后++運(yùn)算符
        let tmp = s1
        s1 += Size(width: 1, height: 1)
        return tmp
    }
    
    static func == (_ s1: Size, _ s2: Size) -> Bool { //判斷相等
        return (s1.width == s2.width)&&(s1.height == s2.height)
    }
}

Equatable

  1. Equatable協(xié)議
  • 想確定2個(gè)實(shí)例是否等價(jià)尖飞,一般是遵守Equatable協(xié)議症副,重載==運(yùn)算符
  • 與此同時(shí),等價(jià)于重載了** != **運(yùn)算符
  1. Swift提供默認(rèn)的Equatable實(shí)現(xiàn)
  • 沒(méi)有關(guān)聯(lián)類型的枚舉
  • 只遵守Equatable協(xié)議關(guān)聯(lián)類型的枚舉
  • 只遵守Equatable協(xié)議存儲(chǔ)屬性的結(jié)構(gòu)體(即如果結(jié)構(gòu)體中的某些實(shí)例屬性未遵守政基,則不行)
  1. 引用類型比較存儲(chǔ)的地址值是否相等(是否引用同一個(gè)對(duì)象) 使用(=== 贞铣、!==)
class Person : Equatable {//不遵守 重載==運(yùn)算符也可以 
//作用:
//1、聲明Person可以使用==判斷 可以調(diào)用下面的equals函數(shù)
//2沮明、自動(dòng)重載 != 運(yùn)算符
    var age: Int
    init(age: Int) {
        self.age = age
    }
    static func == (p1 :Person,p2 :Person) -> Bool {
        p1.age == p2.age
    }
}

var p1 = Person(age: 10)
var p2 = Person(age: 10)
print(p1 == p2)//true

//只有遵守Equatable協(xié)議的泛型才可以使用該函數(shù)
func equals<T :Equatable>(_ t1: T,_ t2: T) -> Bool{
    t1 == t2
}

print(equals(p1, p2))//true
//無(wú)關(guān)聯(lián)類型的的枚舉
enum Season: Equatable {
    case spring,summer,autoum,winter
}
var season1 = Season.winter
var season2 = Season.spring

print(season1 == season2)//false
print(season1 != season2)//true 自動(dòng)重載!=運(yùn)算符

//只遵守Equatable協(xié)議關(guān)聯(lián)類型的枚舉
enum Score: Equatable {
    case score(Int)
    case grade(String)
}

var score1 = Score.score(80)
var score2 = Score.score(90)

print(score1 == score2)//false
print(score1 != score2)//true 自動(dòng)重載!=運(yùn)算符


//只擁有遵守Equatable協(xié)議的存儲(chǔ)屬性的結(jié)構(gòu)體
class Person {
    var age: Int
    init(age: Int) {
        self.age = age
    }
}

struct Point : Equatable{
//    static func == (lhs: Point, rhs: Point) -> Bool {//因?yàn)镻erson未遵守 所以需要重載==運(yùn)算符
//        lhs.x == rhs.x &&
//        lhs.y == rhs.y &&
//        lhs.a == rhs.a &&
//        lhs.p.age == rhs.p.age
//    }
    //遵守Equatable的結(jié)構(gòu)體
    var x: Int ,y: Int
    var a :Array = [Int]()//可想而知Int辕坝、Array等常用數(shù)據(jù)類型是遵守Equatable協(xié)議的
    //var p :Person = Person(age: 10)//如果其存儲(chǔ)屬性未遵守Equatable協(xié)議 則必須重載==運(yùn)算符
    
}

var p1 = Point(x: 10, y: 20)
var p2 = Point(x: 10, y: 20)
print(p1 == p2)//true
print(p1 != p2)//false 自動(dòng)重載!=運(yùn)算符
var p1 = Person(age: 10)
var p2 = p1
print(p1 === p2)//引用類型比較存儲(chǔ)的地址是否相等(是否引用同一個(gè)對(duì)象)
Comparable
  • 想要比較兩個(gè)實(shí)例的大小:遵守Comparable協(xié)議荐健,重載相應(yīng)的運(yùn)算符
//比較兩個(gè)學(xué)生的能力 成績(jī)優(yōu)先 成績(jī)相同酱畅,年齡小更優(yōu)秀
struct Student : Comparable {
    
    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 age :Int
    var score :Int
}

var student1 = Student(age: 10, score: 69)
var student2 = Student(age: 12, score: 69)
var student3 = Student(age: 11, score: 89)
var student4 = Student(age: 13, score: 89)

print(student1 > student2) //true
print(student1 >= student3)//false
print(student3 < student4) //false
print(student3 <= student4)//false
print(student1 <= student4)//true
自定義運(yùn)算符

在全局作用域中使用opretor進(jìn)行聲明

  • prefix opretor 前綴運(yùn)算符
  • postfix opretor 后綴運(yùn)算符
  • infix opretor 中綴運(yùn)算符 : 優(yōu)先級(jí)組(需要定義結(jié)合性琳袄、優(yōu)先級(jí)等等)
自定運(yùn)算符實(shí)例 --前后自減運(yùn)算符 +- 前加后減
prefix operator --
postfix operator --

infix operator +- : PlusMinusPrecedence
precedencegroup PlusMinusPrecedence{
    associativity: none
    higherThan: AdditionPrecedence
    lowerThan: MultiplicationPrecedence
    assignment: true
}

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  -- (p1:inout Point) -> Point{
        p1 = p1 - Point(x: 1, y: 1)
        return p1
    }
    
    static postfix func  -- (p1:inout Point) -> Point{
        let tmp = p1
        p1 = p1 - Point(x: 1, y: 1)
        return tmp
    }
    
    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 ?? 0 + p2.x, y: p1?.y ?? 0 - p2.y)
    }
}

var point1 = Point(x: 10, y: 20)
var point2 = Point(x: 11, y: 22)
print(--point1)//point1 : Point(x: 9, y: 19) 先計(jì)算,再輸出 Point(x: 9, y: 19)
print(point1--)//point1 : Point(x: 8, y: 18) 先輸出Point(x: 9, y: 19)纺酸,再自減
print(--point1 - point1--)//結(jié)果為:Point(x: 0, y: 0) =讯骸!餐蔬!會(huì)出現(xiàn)歧義碎紊,所以Swift去除自增自減是明智的

擴(kuò)展(Extension)

什么是擴(kuò)展
  1. Swift中的擴(kuò)展,類似于OC中的分類(Category)
  2. 擴(kuò)展可以為枚舉用含、結(jié)構(gòu)體矮慕、類、協(xié)議添加新功能
  • 可以添加方法啄骇、計(jì)算屬性痴鳄、下標(biāo)、(便捷)初始化器缸夹、嵌套類型痪寻、協(xié)議等
  1. 擴(kuò)展不能辦到的事情(不能影響內(nèi)存結(jié)構(gòu)以及破壞安全性)
  • 不能覆蓋原有功能(OC可以覆蓋)
  • 不能添加存儲(chǔ)屬性 (OC通過(guò)runtime添加)
  • 不能添加父類
  • 不能添加指定初始化器,不能添加反初始化器
    ...
添加方法虽惭、計(jì)算屬性橡类、下標(biāo)、嵌套類型
//新增計(jì)算屬性
extension Double{
    var km:Double { self * 1_000.0 }
    var m:Double { self }
    var dm:Double { self / 10.0 }
    var cm:Double { self / 100.0 }
    var mm:Double { self / 1_000.0 }
}

var d = 100.0
print(d.km)//100000.0
print(d.m) //100.0
print(d.dm)//10.0
print(d.cm)//1.0
print(d.mm)//0.1

//新增下標(biāo)
extension Array{
    //避免數(shù)組下標(biāo)越界
    subscript(nullable idx: Int) -> Element?{
        if (startIndex..<endIndex).contains(idx){
            return self[idx]
        }
        return nil
    }
}

var arr = [10,20,30]
print(arr[nullable: 5])//輸出:nil

//新增方法
extension Int {
    //重復(fù)某個(gè)方法
    func repeats(task:() -> Void) {
        for _ in 0..<self {
            task()
        }
    }
    
    //新增方法 返回該數(shù)的平方數(shù)
    mutating func square() -> Int {
        self = self * self
        return self
    }
    
    //新增計(jì)算屬性 判斷正負(fù)號(hào)
    enum Kind {
        case negative,zero,positive
    }
    var kind :Kind {
        switch self {
        case 0:
            return .zero
        case let x where x > 0 :
            return .positive
        default:
            return .positive
        }
    }
    
    //獲取第*位數(shù)字
    subscript(digitIndex: Int) -> Int{
        var decimalBase = 1
        for _ in 0 ..< digitIndex{
            decimalBase *= 10
        }
        return (self / decimalBase) % 10
    }
}

var num = 10
num.repeats {
    print("hello!")//重復(fù)打印10次
}

print(num.square())//輸出:100

print(num.kind)//輸出:positive

print(num[2])//十位為1 輸出:1 
初始化器
  • 如果希望自定義初始化器的同時(shí)芽唇,編譯器也能夠生成默認(rèn)初始化器顾画,可以在擴(kuò)展中添加
  • 類遵守協(xié)議實(shí)現(xiàn)的required初始化器,不能寫在擴(kuò)展中
class Person{
    var age :Int
    var name :String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}

extension Person : Equatable{
    static func == (lhs: Person, rhs: Person) -> Bool {
        lhs.age == rhs.age && lhs.name == rhs.name
    }
    convenience init() {
        self.init(age:10,name:"蓋倫")
    }
}

var p1 = Person()
print(p1.age,p1.name)//輸出:10 蓋倫


struct Point {
    var x: Int = 0
    var y: Int = 0
}

extension Point{
    init(_ point: Point) {
        self.init(x: point.x, y: point.y)
    }
}

//編譯器生成默認(rèn)初始化器匆笤,同時(shí)可以自定義初始化器
var po1 = Point()
var po2 = Point(x: 10)
var po3 = Point(y: 10)
var po4 = Point(x: 10,y: 10)
var po5 = Point(po4)
協(xié)議
  1. 如果一個(gè)類已經(jīng)實(shí)現(xiàn)了協(xié)議中的所有要求研侣,但是還沒(méi)有聲明它遵守了這個(gè)協(xié)議,則可以通過(guò)擴(kuò)展讓他遵守這個(gè)協(xié)議
  2. 擴(kuò)展可以給協(xié)議提供默認(rèn)實(shí)現(xiàn)炮捧,也間接實(shí)現(xiàn)「可選協(xié)議的效果」
  3. 擴(kuò)展可以給協(xié)議擴(kuò)從「協(xié)議中從未聲明過(guò)的方法」
//示例1
protocol TestProcotol {
    func test()
}

class Person {
    func test() {
        print("test")
    }
}

extension Person :TestProcotol{

}
//示例1
//BinaryInteger 是Int UInt8 UInt16等共同遵循的協(xié)議
//方法一:
func isOdd<T: BinaryInteger>(_ i:T)-> Bool{
    i % 2 != 0
}
print(isOdd(5))//輸出:true

//方法二:給協(xié)議擴(kuò)展方法
extension BinaryInteger{
    func isOdd() -> Bool {
        self % 2 != 0
    }
}
print(5.isOdd())//輸出:true
protocol TestProcotol {
    func func1()
}

class Person :TestProcotol {
    //如果擴(kuò)展中沒(méi)有實(shí)現(xiàn)庶诡,則必須實(shí)現(xiàn)協(xié)議中的方法 否則編譯報(bào)錯(cuò)
    func func1() {
        print("PersonClass func1")
    }
    
    func func2() {
        print("PersonClass func2")
    }
}

//如果可以在協(xié)議擴(kuò)展中實(shí)現(xiàn)或補(bǔ)充 繼承該協(xié)議的類可以不用實(shí)現(xiàn)協(xié)議中的方法
extension TestProcotol{
    func func1() {
        print("extension func1")
    }
    func func2() {
        print("extension func2")
    }
}

var person :TestProcotol = Person()
//func1在擴(kuò)展中已經(jīng)實(shí)現(xiàn)
person.func1()//PersonClass func1
//func2在原協(xié)議中沒(méi)有
person.func2()//extension func2

疑問(wèn):為什么func2()輸出會(huì)不同呢?
如果person實(shí)例后面沒(méi)有加TestProcotol 則輸出為PersonClass func2 加了之后就是extension func2 因?yàn)樵瓍f(xié)議中沒(méi)有聲明func2咆课,因此:
原協(xié)議中有的方法末誓,優(yōu)先實(shí)例對(duì)象中實(shí)現(xiàn)的方法
原協(xié)議中沒(méi)有的方法,如果實(shí)例有聲明該協(xié)議书蚪,則優(yōu)先協(xié)議擴(kuò)展中的方法喇澡;沒(méi)有聲明,優(yōu)先自己

泛型
  • 擴(kuò)展中依然可以使用原類型中的泛型類型
  • 泛型符合條件才擴(kuò)展
class Stack <Element>{
    var elements = [Element]()
    init(_ numbers:Element...) {
        self.elements = numbers
    }
    func push(_ element:Element) {
        elements.append(element)
    }
    func pop() -> Element {
        elements.removeLast()
    }
    
}

//泛型中依然可以使用原類型中的擴(kuò)展
extension Stack{
    func top() -> Element {
        elements.last!
    }

    func size() -> Int {
        elements.count
    }
}

//符合條件才擴(kuò)展
extension Stack where Element : Equatable{
    static func == (left:Stack,right:Stack) -> Bool {
        left.elements == right.elements
    }
}

var s1 = Stack(10,20,30)
var s2 = Stack(10,20,30)
print(s1 == s2)//true

var s3 = Stack(Stack(10),Stack(20),Stack(30))//元素不符合
var s4 = Stack(10,20,30)
print(s3 == s4)//元素不符合 編譯報(bào)錯(cuò) 
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末善炫,一起剝皮案震驚了整個(gè)濱河市撩幽,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖窜醉,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件宪萄,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡榨惰,警方通過(guò)查閱死者的電腦和手機(jī)拜英,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)琅催,“玉大人居凶,你說(shuō)我怎么就攤上這事√俾眨” “怎么了侠碧?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)缠黍。 經(jīng)常有香客問(wèn)我弄兜,道長(zhǎng),這世上最難降的妖魔是什么瓷式? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任替饿,我火速辦了婚禮,結(jié)果婚禮上贸典,老公的妹妹穿的比我還像新娘视卢。我一直安慰自己,他們只是感情好廊驼,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布据过。 她就那樣靜靜地躺著,像睡著了一般妒挎。 火紅的嫁衣襯著肌膚如雪蝶俱。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天饥漫,我揣著相機(jī)與錄音,去河邊找鬼罗标。 笑死庸队,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的闯割。 我是一名探鬼主播彻消,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼宙拉!你這毒婦竟也來(lái)了宾尚?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎煌贴,沒(méi)想到半個(gè)月后御板,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡牛郑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年怠肋,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淹朋。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡笙各,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出础芍,到底是詐尸還是另有隱情杈抢,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布仑性,位于F島的核電站惶楼,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏虏缸。R本人自食惡果不足惜鲫懒,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望刽辙。 院中可真熱鬧窥岩,春花似錦、人聲如沸宰缤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)慨灭。三九已至朦乏,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間氧骤,已是汗流浹背呻疹。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留筹陵,地道東北人刽锤。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像朦佩,于是被迫代替她去往敵國(guó)和親并思。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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