Swift closure

Closures are self-contained blocks of functional code that can be used in code or used as parameters to pass values.

Closures in Swift are similar to blocks of code in C and Objective-C, as well as anonymous functions in some other programming languages.

Global functions and nested functions are actually special closures.

Closures take the form of:

The global function Nested functions The closure expression
There is a name but no value can be captured. With a name, you can also capture values within a closed function. Nameless closures, using lightweight syntax, capture values based on context.

There are many optimizations for closures in Swift:

  1. Infer parameters and return value types from context
  2. Implicitly returned from a single-line expression closure (i.e. the closure has only one line of code that omits the return)
  3. You can use simplified parameter names such as $0, $1 (starting from 0, for the first argument...)
  4. Trailing closure syntax is available
  5. Grammar

    The following defines a receive parameter and returns the closure syntax of the specified type:

    {(parameters) -> return type in
       statements
    }
    

    Instance

    import Cocoa
    
    let studname = { print("Swift 闭包实例。") }
    studname()
    

    The output of the above program execution is:

    Swift 闭包实例。
    

    The following closures receive two parameters and return boolean values:

    {(Int, Int) -> Bool in
       Statement1
       Statement 2
        ---
       Statement n
    }
    

    Instance

    import Cocoa
    
    let divide = {(val1: Int, val2: Int) -> Int in 
       return val1 / val2 
    }
    let result = divide(200, 20)
    print (result)
    

    The output of the above program execution is:

    10
    

    The closure expression

    Closure expressions are a way to build inline closures using concise syntax. C losure expressions provide some syntax optimizations that make it easy to compose closures.


    Sort function

    The Swift Standard Library provides a function called sort that sorts the values in an array of known types based on the closure functions you provide for sorting.

    When sorting is complete, the sort(:)method returns a new array the same size as the original array, containing elements of the same type and the elements are sorted correctly, and the original array is not modified by the sort(:)method.

    The sort(:)method needs to pass in two parameters:

  • An array of known types
  • The closure function, which needs to pass in two values of the same type as the array element and return a Boolean type value to indicate whether the first argument passed in after sorting ends before or after the second argument. If the first argument value appears before the second argument value, the sort closure function needs to return true and, conversely, false

Instance

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

// 使用普通函数(或内嵌函数)提供排序功能,闭包函数类型需为(String, String) -> Bool。
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sort(backwards)

print(reversed)

The output of the above program execution is:

["S", "D", "BE", "AT", "AE"]

If the first string (s1) is larger than the second string (s2), the backwards function returns true, indicating that s1 should appear before s2 in the new array. F or characters in a string, "greater than" means "appears later in alphabetical order." T his means that the letter "B" is greater than the letter "A" and the string "S" is greater than the string "D". I t will be sorted in reverse order, and "AT" will come before "AE".


The argument name abbreviation

Swift automatically provides parameter name abbreviations for inline functions, and you can call closed parameters in order directly from $0, $1, $2.

Instance

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

var reversed = names.sort( { $0 > $1 } )
print(reversed)

$0 and $1 represent the parameters of the first and second String types in the closure.

The output of the above program execution is:

["S", "D", "BE", "AT", "AE"]

If you use parameter name abbreviations in a closed expression, you can omit the definition from the list of closed parameters, and the type of the corresponding parameter name abbreviation is inferred from the function type. The in keyword can also be omitted.


The operator function

There is actually a shorter way to write the closed expression in the example above.

String type defines a string implementation that is > than the number , which accepts two String-type arguments String and returns the value of the Bool type. T his coincides with the type of function required for the second argument of the sort(_:) method. Therefore, you can simply pass a string function larger than the sign, and Swift can automatically infer that you want to implement a string function that is larger than the number:

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

var reversed = names.sort(>)
print(reversed)

The output of the above program execution is:

["S", "D", "BE", "AT", "AE"]

Trailing closures

Trailing a closure is a closed expression written after the parenthesis of a function that supports calling it as the last argument.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体部分
}

// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
    // 闭包主体部分
})

// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
  // 闭包主体部分
}

Instance

import Cocoa

let names = ["AT", "AE", "D", "S", "BE"]

//尾随闭包
var reversed = names.sort() { $0 > $1 }
print(reversed)

Sort () after the s.$0 and $1 is the trailing closure.

The output of the above program execution is:

["S", "D", "BE", "AT", "AE"]

Note: If the function only needs one argument to the closure expression, you can even omit () closures.

reversed = names.sort { $0 > $1 }

Capture the value

Closures can capture constants or variables in the context of their definition.

Closures can reference and modify these values inside the closure function, even if the primary domain that defines these constants and variables no longer exists.

Swift's simplest form of closure is nested functions, which are functions that are defined in the body of functions in other functions.

Nested functions capture all the parameters of their external functions, as well as defined constants and variables.

Look at this example:

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

A function makeIncrementor, which has an Int-type parameter ameout, and it has an external parameter name for Incremet, which means that when you call, you must use that external name. The return value is ()-> Int

Within the function question, the variable runningTotal and a function incrementor are declared.

The incrementor function does not get any arguments, but the runningTotal andamount variables are accessed inside the function. This is because it is implemented by capturing runningTotal and amount variables that already exist in the function that contains it.

Since theamount variable is not modified, incrementor actually captures and stores a copy of the variable, which is stored with the incrementor.

So when we call this function, it adds up:

import Cocoa

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// 返回的值为10
print(incrementByTen())

// 返回的值为20
print(incrementByTen())

// 返回的值为30
print(incrementByTen())

The output of the above program execution is:

10
20
30

Closures are reference types

In the example above, incrementByTen is a constant, but the closures that these constants point to can still increase the value of the variables it captures.

This is because both functions and closures are reference types.

Whether you assign a function/closure to a constant or a variable, you are actually setting the value of the constant/variable to a reference to the function/closure. In the example above, the reference to the closure byTen is a constant, not the closure content itself.

This also means that if you assign a closure to two different constants/variables, both values point to the same closure:

import Cocoa

func makeIncrementor(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementor() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementor
}

let incrementByTen = makeIncrementor(forIncrement: 10)

// 返回的值为10
incrementByTen()

// 返回的值为20
incrementByTen()

// 返回的值为30
incrementByTen()

// 返回的值为40
incrementByTen()

let alsoIncrementByTen = incrementByTen

// 返回的值也为50
print(alsoIncrementByTen())

The output of the above program execution is:

50