Swift advanced (XV) extension

Time:2021-11-29
  • The extension in swift is somewhat similar to the category in OC
  • Extension can beenumerationstructural morphologyclassagreementAdd new features
    □ you can add methods, calculation attributes, subscripts, (convenient) initializers, nested types, protocols, etc
  • What extensions can’t do:
    □ original functions cannot be overwritten
    □ you cannot add storage attributes or add attribute observers to existing attributes
    □ cannot add parent class
    □ the specified initializer and de initializer cannot be added
    ……

Calculation property, subscript, method, nested type

  • Add calculation attribute (the essence of calculation attribute is method)
extension Double {
    var km: Double { self * 1_000.0}
    var m: Double { self }
    var dm: Double { self / 100.0 }
    var cm: Double { self / 10.0 }
    var mm: Double { self / 1_000.0 }
}
  • Add subscript
    ElementyesArrayThe original generics can be viewed byArrayhear
extension Array {
    subscript(nullable idx: Int) -> Element? {
        if (startIndex ..< endIndex).contains(idx) {
            return self[idx]
        }
        return nil
    }
}
  • Add method, nested type
extension Int {
    func repetitions(task: () -> Void) {
        for _ in 0..<self {
            task()
        }
    }
    
    mutating func square() -> Int {
        self = self * self
        return self
    }
    
    enum Kind {
        case negative
        case zero
        case 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
    }
    
}

Protocol initializer

  • If you wantCustom initializerAt the same time, the compiler can also generateDefault initializer
    □ yesExtensionWritten inCustom initializer
  • requiredInitializers cannot be written in extensions
  • Extended protocol
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
    }
    
    //Convenient initializer
    convenience init() {
        self.init(age: 0, name: "")
    }
}
  • Extension initializer
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()
var p2 = Point(x: 10, y: 20)
var p3 = Point(x: 10)
var p4 = Point(y: 20)
var p5 = Point(p2)

agreement

  • If a type has implemented all the requirements of the protocol, but has not declared that it complies with the protocol, it can be extended to make it comply with the protocol
protocol MyProtocol {
    func test()
}

class test {
    func test() {
        print("name")
    }
}
extension test: MyProtocol {}
  • Write a function to judge whether an integer is odd
    □ generally, we will write as follows:
func isOdd(_ i: Int) -> Bool {
    (i % 2) != 0
}

print(isOdd(4))
/*Output results*/
false

You should be clear that the above writing is not rigorous. If you pass in oneUIntAnd?

Swift advanced (XV) extension

image.png

How should we deal with it?
Because all integers obeyBinaryIntegerBy agreement, we can:
□ the first method uses generics and defines generics

func isOdd<T: BinaryInteger>(_ i: T) -> Bool {
    (i % 2) != 0
}

□ giveBinaryIntegerIt is better to add extensions to the protocol

extension BinaryInteger {
    func isOdd() -> Bool {
        (self % 2) != 0
    }
}

print(3.isOdd())
/*Output results*/
true
  • Extension can provide default implementation or indirect implementation for the protocolOptional ProtocolEffect of
  • Extensions can supplement the protocolMethods never stated in the agreement
protocol MyProtocol {
    func fun1()
}

extension MyProtocol {
    func fun1() {
        print("MyProtocol fun1")
    }
    func fun2() {
        print("MyProtocol fun2")
    }
}

We all know that as long as we abide by the agreement, we must implement the methods stated in the agreement; However, we can provide a default implementation in the extension of the protocol so that it can be implementedOptional Protocol:

class Person: MyProtocol {}
var p = Person()
p.fun1() // MyProtocol fun1
p.fun2() // MyProtocol fun2

Of course, if we implement the protocol method in the class, we will also implement the implementation in the class:

class Person: MyProtocol {
    func fun1() {
        print("Person fun1")
    }
    func fun2() {
        print("Person fun2")
    }
}
var p = Person()
p.fun1() // Person fun1
p.fun2() // Person fun2

Here’s oneNote:
As follows,pDeclaration of complianceMyProtocolProtocol type, actuallyPerson; But when the method is called, there is noMyProtocolMethods and objects declared in the protocol but implemented by default in the extensionpIf called, the default method in the protocol extension will be executed.

var p: MyProtocol = Person()
p.fun1() // Person fun1
p.fun2() // MyProtocol fun2

This is because,fun2If it is not declared in the protocol, the compiler is not sure whether the class complying with it implements the method. All default methods implemented in the protocol extension take precedence.
Ifvar p = Person(), written in this way, does not tell the compiler that it is compliantMyProtocolThe object of the protocol just tells the compiler that it isPersonObject, so priority is given to executionPersonThe method inside.

generic paradigm

class Stack<E> {
    var elements = [E]()
    func push(_ element: E) {
        elements.append(element)
    }
    func pop() -> E {
        elements.removeLast()
    }
    func size() -> Int {
        elements.count
    }
}

//The generic type in the original type can still be used in the extension
extension Stack {
    func top() -> E {
        elements.last!
    }
}

//Extend only when conditions are met
extension Stack : Equatable where E : Equatable {
    static func == (left: Stack, right: Stack) -> Bool {
        left.elements == right.elements
    }
}

Recommended Today

On the mutation mechanism of Clickhouse (with source code analysis)

Recently studied a bit of CH code.I found an interesting word, mutation.The word Google has the meaning of mutation, but more relevant articles translate this as “revision”. The previous article analyzed background_ pool_ Size parameter.This parameter is related to the background asynchronous worker pool merge.The asynchronous merge and mutation work in Clickhouse kernel is completed […]