19-擴充套件

Fat brother發表於2020-11-27

擴充套件(Extension)

  • Swift 中的擴充套件,有點類似於 OC 中的分類)(Category)
  • 擴充套件可以為列舉、結構體、類、協議新增新功能
    可以新增方法、計算屬性、下標、(便捷)初始化器、巢狀型別、協議等
  • 擴充套件不能辦到的事情
  1. 不能覆蓋原有的功能
  2. 不能新增儲存屬性,不能向已有的屬性新增屬性觀察器
  3. 不能新增父類
  4. 不能新增指定初始化器

計算屬性、下標、方法、巢狀型別

// 計算屬性
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 }
}

// 下標
extension Array {
    subscript(nullable idx: Int) -> Element? {
        if (startIndex..<endIndex).contains(idx) {
            return self[idx]
        }
        
        return nil
    }
}

extension Int {
    // 方法
    func repetitions(task: () -> Void) {
        for _ in 0..<self { task() }
    }
    
    mutating func square() -> Int {
        self = self * self
        return self
    }
    
    // 巢狀型別
    enum Kind { case negative, zer0, positive }
    var kind: Kind {
        switch self {
        case 0: return .zer0
        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
    }
}

初始化器與便捷初始化器

// 普通的初始化器
class Person {
    var age: Int
    var name: String
    init(age: Int, name: String) {
        self.age = age
        self.name = name
    }
}
// 便捷初始化器
extension Person {
    static func == (left: Person, right: Person) -> Bool {
        left.age == right.age && left.name == right.name
    }
    
    convenience init() {
        self.init(age: 0, name: "Tony")
    }
}

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

// 在 extension 中定義自定義初始化器
extension Point {
    init(_ point: Point) {
        self.init(x: point.x, y: point.y)
    }
}

var p1 = Point()
var p2 = Point(x: 10)
var p3 = Point(y: 20)
var p4 = Point(x: 10, y: 20)
var p5 = Point(p4)
  • 如果希望自定義初始化器的同時,編譯器也能預設生成初始化器:
  1. 可以在擴充套件中編寫自定義初始化器
  2. required初始化器不能寫在擴充套件中

協議

  • 如果一個型別已經實現了協議的所有要求,但是還沒有宣告它遵守了這個協議,可以通過擴充套件來讓他遵守這個協議
protocol TestProtocol {
    func test()
}

class TestClass {
    func test() {
        print("test")
    }
}
extension TestClass: TestProtocol {}
  • 編寫一個函式,判斷一個整數是否為奇數
// BinaryInteger 在 Swift 中代表所有整數
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("TestProtocol test1")
    }

    func test2() {
        print("TestProtocol test2")
    }
}

class TestClass: TestProtocol {}
var cls = TestClass()
cls.test1()  // TestProtocol test1
cls.test2()  // TestProtocol test2

var cls2: TestProtocol = TestClass()
cls.test1()  // TestProtocol test1
cls2.test2() // TestProtocol test2
protocol TestProtocol {
    func test1()
}

extension TestProtocol {
    func test1() {
        print("TestProtocol test1")
    }
    
    func test2() {
        print("TestProtocol test2")
    }
}

class TestClass: TestProtocol {
    func test1() {
        print("TestClass test1")
    }
    
    func test2() {
        print("TestClass test2")
    }
}
var cls = TestClass()
cls.test1()  // TestClass test1
cls.test2()  // TestClass test2

var cls2: TestProtocol = TestClass()
cls.test1()  // TestClass test1
cls2.test2() // TestProtocol test2

泛型

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
    }
}

相關文章