高级运算符

溢出运算符 (Overflow Operator)

  • Swift的算术运算符出现溢出时会抛出运行时错误
  • Swift有溢出运算符 &+、&-、&*, 用来支持溢出运算
print(UInt8.min) //0
print(UInt8.max) //255

var v1 = UInt8.max // 255
//v1 += 1  超出了范围  直接报错
var v2 = v1 &+ 1
print("v2",v2)// 0
// 使用溢出运算符可以避免报错,但+是在范围内循环的
v2 = v1 &* 2
print("v2",v2)// 254 即为 v2 = v1 &+ v1

运算符重载 (Operator reload)

// 运算符重载
struct Point {
    var x = 0, y = 0
    static func + (p1: Point, p2: Point) -> Point {
        Point(x: p1.x + p2.x, y: p1.y + p2.y)
    }
    static prefix func - (p1: Point) -> Point {
        Point(x: -p1.x, y: -p1.y )
    }
    static func += (p1: inout Point, p2: Point) {
        
        开 p1 = p1 + p2
    }
}
//func + (p1: Point, p2: Point) -> Point {
//    return Point(x: p1.x + p2.x, y: p1.y + p2.y)
//}
var p1 = Point(x: 10, y: 20)
var p2 = Point(x: 11, y: 22)
var p3 = Point(x: 12, y: 33)

let p4 = p1 + p2 + p3

print(p4)

Equatable

  • 要想知道2个实例是否等价, 一般做法是遵守Equatable协议, 重载 == 运算符
    • 与此同时, 等价于重载了 != 运算符
 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

  • Swift为以下类型提供默认的Equatable实现

    • 没有关联类型的枚举
    • 只拥有遵守Equatable协议关联类型的枚举
    • 只拥有遵守Equatable协议存储属性的结构体
  • 引用类型比较存储的地址值是否相等(是否引用着同一个对象), 使用恒等运算符=== 、!===

Comparable

  • 要比较2个实例的大小, 一般的做法是:
    • 遵守Comparable 协议
    • 重载相应的运算符

自定义运算符 (Custom Operator)

  • 可以自定义新的运算符: 在全局作用域使用operator进行声明
prefix operator 前缀运算符
postfix operator 后缀运算符
infix operator 中缀运算符: 优先级组
precedencegroup 优先级组 {
    associativity: 结合性(left/right/none)
    higherThan: 比谁的优先级高
    lowerThan: 比谁的优先级低
    assignment: true代表在可选链操作中拥有跟赋值运算符一样的优先级
}

扩展 (Extension)

  • Swift 中的扩展,有点类似OC中的Category
  • 扩展可以为枚举、结构体、类、协议添加新功能
    • 可以添加方法、计算属性、下标、(便捷)初始化器、嵌套类型、协议等
  • 扩展不能办到的事情
    • 不能覆盖原有的功能
    • 不能添加存储属性,不能像已有的属性添加属性观察器
    • 不能添加父类
    • 不能添加指定初始化器,不能添加反初始化器
    • 。。。
extension Double {
    var km: Double { self / 1000.0}
    var m: Double { self }
    var dm: Double { self * 10.0}
    var cm: Double { self * 100.0}
    var mm: Double { self * 1000.0}
}
var d = 100.0
print(d.km) // 0.1
print(d.m)  // 100.0
print(d.dm) // 1000.0
print(d.cm) // 10000.0

// 添加下标给Array
extension Array {
    subscript(nullable idex: Int) -> Element? {
        if (startIndex..<endIndex).contains(idex) {
            return self[idex]
        }
        return nil
    }
}
var arr: Array<Int> = [10, 20, 30]
print(arr[nullable: 2] as Any)
print(arr[nullable:4] as Any)

// 给Int类型添加功能
extension Int {
    func repeats(task: () -> Void) {
        for _ in 0..<self { task() }
    }
    mutating func square() -> Int {
        self = self * self
        return self
    }
    // 嵌套类型
    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 .negative
        }
    }
    subscript(digitIndex: Int) -> Int {
        var decimalBase = 1
        for _ in 0..<digitIndex { decimalBase *= 10}
        return (self / decimalBase) % 10
    }
}
3.repeats {
    print(1)
}
// 1 1 1 打印3次1
var age = 123
print(age.square())
// 15129 就是123的平方
print(10.kind)
// positive 10的类型是 positive
print(age[1])
// 2 打印十位上的数字

协议 初始化器

  • 如果希望自定义初始化器的同时,编译器也能够生成默认初始化器
    • 可以在扩展中编写自定义初始化器
  • required初始化器,不能写在扩展中
class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age  = age
        self.name = name
    }
}
extension Person : Equatable {
    static func == (left: Person, rigtht: Person) -> Bool {
        left.age == rigtht.age && left.name == rigtht.name
    }
    convenience init() {
        self.init(age: 0, name: "")
    }
}
struct Point {
    var x: Int = 0
    var y: Int = 0
}
extension Point {
    init(_ point: Point) {
        self.init(x: point.x, y: point.y)
    }
}
var p1 = Point(x: 10)
var p2 = Point(p1)
  • 如果一个类型已经实现了协议的所有要求,但是还没有声明它遵守了这个协议,可以通过扩展来让它遵守这个协议
protocol TestProtocol {
    func test()
}
class TestClass {
    func test() {
        print("test")
    }
}
extension TestClass : TestProtocol { }
// 编写一个函数,判断一个整数是否为奇数
func isOdd <T: BinaryInteger>(_ i: T) -> Bool { i % 2 != 0 }
extension BinaryInteger {
    func isOdd() -> Bool { self % 2 != 0 }
}
  • 扩展可以给协议提供默认实现,也间接实现 可选协议 的效果
  • 扩展可以给协议扩充 协议中从未声明过的方法
protocol TestProtocol {
    func test1()
}
extension TestProtocol {
    func test1() {
        print("Protocol test1")
    }
    func test2() {
        print("Protocol test2")
    }
    static func test3() {
        print("Protocol test3")
    }
}
/*
 class TestClass : TestProtocol { }
var cls = TestClass()
cls.test1()
cls.test2()
TestClass.test3()
 */
class TestClass : TestProtocol {
    func test1() {
    print("Class test1")
}
    func test2() {
    print("Class test2")
}}
var cls = TestClass()
cls.test1() // Class test1
cls.test2() // Class test2
TestClass.test3() // Protocol test3

var cls2: TestProtocol = TestClass()
cls2.test1() // Class test1
/// 由于协议里面没有声明test2,所以不确定指向的类有没有实现test2,
/// 所以优先去协议里找,所以调用的是协议里的Protocol test2
cls2.test2() // Protocol test2
TestClass.test3() // Protocol test3

扩展泛型

class Stack<E> {
    var elements = [E]()
    func push(_ element: E) { elements.append(element) }
    func pop() -> E { elements.removeLast() }
    
    func size() -> Int { elements.count }
}
// 扩展中依然可以使用原类型中的泛型类型
extension Stack {
    func top() -> E { elements.last! }
}
// 符合条件才扩展
extension Stack : Equatable where E : Equatable {
    static func == (left: Stack, right: Stack) -> Bool {
        left.elements == right.elements
    }
}