closure

A closure is a function that captures a context constant or variable

Defines a global function that is also a closure but does not capture values

func test(){
    print("test")
}
Copy the code

Incrementer is a closure function that captures the makeIncrementer variable runningTotal

Func makeIncrementer() -> () -> Int{var runningTotal = 10 // The embedded function is a closure func incrementer() -> Int{runningTotal += 1 return runningTotal } return incrementer }Copy the code

Closure expression

{(param) -> ReturnType in // method body}Copy the code

Closure expressions can also be declared as an optional type

var clourse: ((Int) -> Int)?
clourse = nil
Copy the code

A closure is declared as a constant by let, and the closure expression is assigned to clourse, a constant that cannot be changed after assignment

let clourse: (Int) -> Int
clourse = {(age: Int) in
    return age
}
Copy the code

Pass the closure to the function as an argument

func test(param: () -> Int) {
    print(param())
}

var age = 10

test {() -> Int in
    return age
}
Copy the code

Following the closure

Func test(_ a: Int, _ b: Int, _ c: Int, by: (_ item1: Int, _ item2: Int, _ item3: func (_ a: Int, _ b: Int, _ c: Int, by: (_ item1: Int, _ item2: Int, _ item3: Int) -> Bool) -> Bool{return by(a, b, c)} by: {(item1: Int, item2: Int, item3: Bool) -> Bool{return by(a, b, c)} Int) -> Bool in return (item1 + item2 < item3)}) item3) -> Bool in return (item1 + item2 < item3) }Copy the code

Capture a variable

As shown, each print increments by 1 because in the function makeIncrementer, the variable runningTotal is captured by the closure incrementer, So the constant makeInc is incremented by 1 each time it is called. Instead, print makeIncrementer()() only once, looking at the sil fileThe essence of capturing values is to open up memory on the heap space to put values in

Closures are reference types

Know the IR

Basic syntax of IR

Elementnumber Specifies the number of elements iN the array. Elementtype specifies the type of elements iN the array. [< elementNumber > x < elementType >] //example alloca[24xi8],align8 24 i8 0 structure T is the structure name, <type list> is the constructor's membership list %swift.refcounted = type {%swift.type*, i64} %T = type {<type list>} pointer type <type> * 64-bit integer The 8-byte i64* Getelementptr instruction passes the getelementptr instruction when retrieving the members of arrays and structures in LLVM, Syntax rules are as follows <result> = getelementptr <ty>, <ty>* <ptrval>{, [inrange] <ty> <id x>}* <result> = getelementptr inbounds <ty>, <ty>* <ptrval>{, [inrange] <ty> <idx>}* An example of how to get a struct or an array of members of the struct munger_struct {int f1; int f2; }; void munge(struct munger_struct *p) { p[0].f1 = p[1].f1 + p[2].f2; // Suppose P is an array of three elements. } struct munger_struct array[3]; int main(int argc, const char * argv[]) { munge(array); // call return 0; } Run the following command to generate the IR file swiftc-emit - IR main.swift > main.llCopy the code

Analysis of the closure

func makeIncrementer() -> () -> Int{
    var runningTotal = 10
    func incrementer() -> Int{
        runningTotal += 1
        return runningTotal
    }
    return incrementer
}
let makeInc = makeIncrementer()
Copy the code

To continue analyzing closures, check out the IR file analysisAccording to the above analysis, to write a copyRestore the 0x0000000100001920 symbol to viewCapture two valuesIr fileCopy writeRestore the function by passing 0x00000001000058C0Print the printed addressAs can be seen from the figure above, in captureValue is the type of captured value passed in, which is similar to the Box structure, except that one more member is added to the Box structure. After output, it is still a box-like structure. Modify the Box structureThe principle of capturing values: the heap is opened up in memory space, captured values into this memory space; Modifying the capture value is modifying the value in the memory space; Closures are reference types (address passing)

Escape a closure

There are two ways to escape a closure: the closure is held by an external property, and the closure is invoked late, both of which extend the closure’s lifetime beyond the function

Automatic closure

Add @autoclosure keyword, can pass function type, also can pass function return value type, automatic closure does not accept any arguments