The swift programming language-official Tutorial: Swift (8) closure -- closures

Source: Internet
Author: User
Tags integer numbers types of functions
Closures are functional self-contained modules that can be passed and used in code. Closures in swift are similar to blocks in C and objective-C, and Lambdas in other programming languages. Closure is acceptable. CaptureAnd store references to any constants and variables in the context. This is the so-called closure and enclose these constants and variables, commonly known as closures. Swift will manage CaptureMemory operations involved in the process.
Note: If you are not familiar with capturing, you do not need to worry about it. We will introduce it in detail later.
The global and nested functions described in the function section are actually special closures. Closures take one of the following three forms: 1. A global function is a closure with a name but no value is captured. 2. A nested function is a closure with a name and can capture the values in the function domain. 3. A closure expression is a closure expression written in lightweight syntax that can capture variables or constant values in its context. A closure expression without a name Swift has a simple style, syntax optimization is also encouraged in common scenarios. The main optimization is as follows: * using context inference parameters and return value types * single-expression) closure can omit the return keyword * abbreviated parameter name * trailing closure syntax Closure expression Nested functions are a method that allows you to conveniently name and define a self-contained code module in complex functions. Of course, sometimes it is very useful to write a small class function structure without complete definition and naming, especially when processing some functions and taking other functions as parameters of the function. Closure expressions are a method of constructing inline closures using concise syntax. The closure expression provides some syntax Optimizations to make it easy and clear to write the closure. The example of the closure expression below demonstrates the sort function definition and syntax optimization through several iterations. Each iteration describes the same function in a more concise way. Sort FunctionThe swift Standard Library provides the sort function, which sorts the values in an array of known types based on the sort closure you provide. Once sorting is completed, the function returns a new array of the same size as the original array, which contains the same type of elements that have been correctly sorted. The following closure expression example uses the sort function StringTypes of arrays are sorted in alphabetical order. The following are the initial array values:
1 let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"] 
The sorting function has two parameters: 1. an array of known type values. 2. A closure uses two parameters of the content of an array of the same type, and returns a Boolean value to indicate whether to put the first value before or after the second value during sorting. If the first value should appear before the second value, the closure needs to return true; otherwise, false is returned. In this example StringType array, so the sort closure must be (string, string)-> bool type function. One way to provide the sort closure is to write a common function that meets its type requirements and pass it as the second parameter of the sort function:
 
1 func backwards(s1: String, s2: String) -> Bool { 
2     return s1 > s2 
3 } 
4 var reversed = sort(names, backwards) 
5 // reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"] 
If the first string (S1) is greater than the second string (S2), the backwards function returns true, indicating that S1 should appear before S2 in the new array. The character "greater than" indicates "appears after the letter order ". This means that the letter "B" is greater than the letter "A", and the string "Tom" is greater than the string "Tim ". It will sort the letters in reverse order, "Barry" will be placed after "Alex", and so on. However, this is a rather lengthy method, essentially simply writing a single expression function (A> B ). In the following example, we can use the closed expression syntax to better construct an inline sort closure. Closure expression syntaxThe syntax of closure expressions is as follows:
 
1 { (parameters) -> returnType in 
2     statements 
3 } 
The closure expression syntax can use constants, variables, and inout types as parameters, but does not provide default values. You can also use variable parameters at the end of the parameter list. Tuples can also be used as parameters and return values. The following example shows the code of the closure expression version corresponding to the backwards function:
1 reversed = sort(names, { (s1: String, s2: String) -> Bool in 
2     return s1 > s2 
3 }) 

It should be noted that the inline closure parameter and return value type declaration are the same as the backwards function type declaration. Both methods are written as (S1: String, S2: string)-> bool type. However, in an inline closure expression, the types of functions and return values are enclosed in braces, rather than outside braces. The function body of the closure is introduced by the keyword in. This keyword indicates that the closure parameters and return value type definitions have been completed, and the closure function body is about to begin. Because the function body of this closure is so short that it can be rewritten into a line of code:


1 reversed = sort(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )  

This indicates that the overall call of the sort function remains unchanged, and a pair of parentheses still enclose the entire parameter set in the function. One of the parameters is now an inline closure (compared to the backwards version code ). Type inferred from contextBecause the sort closure is passed as a function parameter, Swift can infer the type of its parameters and return values. Sort expects the second parameter to be a function of type (string, string)> bool. Therefore, the string, string, and bool types do not need to be part of the closure expression definition. Because all types can be correctly inferred, the return arrow (->) and parentheses around the parameter can also be omitted:


1 reversed = sort(names, { s1, s2 in return s1 > s2 } )  

In fact, in any case, when a closure constructed by an inline closure expression is passed to a function as a parameter, the closure parameters and return value types can be inferred, this means that you hardly need to construct any inline closure using the full format. However, you can also use a clear type. If you want to avoid ambiguity in the reader's reading, it is worth encouraging. In this sorting function example, the purpose of the closure is clear, that is, the sorting is replaced, and it is safe for readers to assume that the closure may use string values, it is used to sort a string array. Return can be omitted in the closure of a single row expression.The closure of a single-row expression can implicitly return the result of a single-row expression by hiding the return keyword. The example in the previous version can be rewritten:

1 reversed = sort(names, { s1, s2 in s1 > s2 } )  

In this example, the second parameter of the sort function specifies that the closure must return a bool value. Because the closure function contains only one single expression (S1> S2), this expression returns the bool type value, so there is no ambiguity here, And the return keyword can be omitted. Abbreviated parameter nameSwift automatically provides the abbreviated parameter name function for inline functions. You can directly reference the value of a closure parameter through a name such as $0, $1, and $2. If you use the abbreviated parameter name in a closure expression, you can omit its definition in the closure parameter list, and the type of the abbreviated parameter name is inferred by the function type. The in keyword can also be omitted, because the closure expression is completely composed of the closure function body:
1 reversed = sort(names, { $0 > $1 } )  
In this example, $0 and $1 represent the first and second string parameters in the closure. Operator FunctionsThere is actually a simpler way to write the closure expression in the above example. Swift's string type defines the implementation of a string greater than (>), so that it can be used as a function to accept two string-type parameters and return bool-type values. This exactly matches the function type required by the second parameter of the sort function. Therefore, you can simply pass a greater than sign, and swift can automatically infer that you want to use a greater than sign string function implementation:
1 reversed = sort(names, >)  
For more information about operator expressions, see operator functions. Trailing Closure If you need to pass a long closure expression as the last parameter to the function, you can use the trailing closure to enhance the readability of the function. The trailing closure is a closure expression that is written outside the function brackets (later). The function supports calling it as the last parameter.
1 func someFunctionThatTakesAClosure (closure: ()-> ()) {
  2 // function body
  3}
  4
  5 // The following is a function call without using the trailing closure
  6
  7 someFunctionThatTakesAClosure ({
  8 // The body of the closure
  9 }) 
10
11 // The following is a function call using a trailing closure
12
13 someFunctionThatTakesAClosure () {
14 // The main body of the closure
15}
Note: If a function only requires a closure expression as a parameter, you can even omit () when you use the trailing closure.
In the preceding example, the string sorting closure that serves as the sort function parameter can be rewritten:
1 reversed = sort(names) { $0 > $1 } 
When the closure is so long that it cannot be written in a row, the trailing closure becomes very useful. For example, Swift's ArrayType has a map method, which obtains a closure expression as its unique parameter. Each element in the array calls the closure function once and returns the value mapped to the element (or different types of values ). The specific ing mode and return value type are specified by the closure. After the array closure function is provided, the map method returns a new array, which contains the values mapped to the original array. The following example describes how to use the trailing closure in the Map Method IntType array [510,] to include the corresponding StringType array ["onesix", "fiveeight", "fiveonezero"]:
1 let digitNames = [
2 0: "Zero", 1: "One", 2: "Two", 3: "Three", 4: "Four",
3 5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
4]
5 let numbers = [16, 58, 510]
The code above creates a ing dictionary between integer numbers and their English names. A string-ready integer array is defined. You can now create a string version array by passing a trailing closure to the map method of numbers. Note that calling numbers. map does not need to contain any parentheses after map, because you only need to pass the closure expression parameter, and the closure expression parameter is written in trailing mode:
1 let strings = numbers.map {
  2 (var number)-> String in
  3 var output = ""
  4 while number> 0 {
  5 output = digitNames [number% 10]! + Output
  6 number / = 10
  7}
  8 return output
  9 } 
10 // The strings constant is inferred to be an array of string type, which is String []
11 // its value is ["OneSix", "FiveEight", "FiveOneZero"]
Map calls a closure expression for each element in the array. You do not need to specify the number type of the input parameter of the closure, because it can be inferred by the array type to be mapped. The closure number parameter is declared as a variable parameter (for details about the variable, see constant and variable parameters). Therefore, you can modify it in the closure function. The closure expression specifies that the return value type is StringTo indicate that the new array type for storing the ing value is String. The closure expression creates a string and returns it each time it is called. The remainder operator (Number % 10) is used to calculate the last digit and the ing string is obtained using the digitnames dictionary.
Note: The dictionary digitnames subscript is followed by an exclamation point (!), Because the dictionary subscript returns an optional value (optional value), it indicates that the search will not fail even if the key does not exist. In the above example, it ensures that Number % 10 can always be used as a valid subscript key for the digitnames dictionary. Therefore, the exclamation mark can be used to store the string type value in the optional subscript items in force-Unwrap.
The string obtained from the digitnames dictionary is added to the front of the output, and a number of the string version is created in reverse order. (In expression Number % 10, if number is 16, 6, 58, 8,510, and 0 are returned ). The number variable is divided by 10. Because it is an integer, not all parts are ignored during calculation. Therefore, 16 is changed to 5,510 and to 51. Repeat the entire process until number/= 10 is 0. The closure will output the string, and the map function will add the string to the mapped array. In the above example, the trailing closure syntax neatly encapsulates the specific closure function after the function, instead of wrapping the entire closure in the brackets of the map function. Caputure) Closures can capture constants or variables in the context they define. Even if the original scope that defines these constants and variables does not exist, the closure can still reference and modify these values in the closure function. Swift's simplest form of closure is nested functions, that is, functions defined in other functions. Nested functions can capture all the parameters of their external functions and defined constants and variables. The following example shows a function called makeincrementor, which contains a nested function called incrementor. The nested function incrementor captures two values from the context: runningtotal and amount. Makeincrementor then returns incrementor as a closure. Each time an incrementor is called, it uses amount as the increment to increase the value of runningtotal.
 
1 func makeIncrementor(forIncrement amount: Int) -> () -> Int { 
2     var runningTotal = 0 
3     func incrementor() -> Int { 
4         runningTotal += amount 
5         return runningTotal 
6     } 
7     return incrementor 
8 }  
Makeincrementor returns the type ()-> Int. This means that it returns a function instead of a simple type value. This function returns only one IntType value. For details about how the function returns other functions, see function types as return types. The makeincrementor function defines an integer variable runningtotal (initially 0) to store the total increase currently. This value is returned through incrementor. Makeincrementor has one IntType parameter. Its external name is forincrement, and its internal name is amount, which indicates the amount of runningtotal to be increased each time the incrementor is called. The incrementor function is used to perform the add operation. This function simply adds amount to runningtotal and returns it. If we look at this function separately, we will find it looks unusual:
1 func incrementor() -> Int { 
2     runningTotal += amount 
3     return runningTotal 
4 }  
The incrementor function does not obtain any parameters, but the runningtotal and amount variables are accessed in the function body. This is because it is implemented by capturing the runningtotal and amount variables that already exist in the function body that contains it. Because the amount variable is not modified, the incrementor actually captures and stores a copy of the variable, and the copy is stored together with the incrementor. However, because the value of runningtotal is changed every time this function is called, incrementor captures the reference of the current runningtotal variable instead of simply copying the initial value of this variable. Capture a reference to ensure that the makeincrementor does not disappear when it ends, and that runningtotal can continue to increase when the incrementor function is executed for the current time.
Note: Swift will decide whether to capture the reference or copy the value. You do not need to mark amount or runningtotal to declare how to use the embedded incrementor function. Swift also processes the memory management operation of the runingtotal variable. If it is no longer used by the incrementor function, it is cleared.
The following is an example of using makeincrementor:
1 let incrementByTen = makeIncrementor(forIncrement: 10)
This example defines a constant called incrementbyten, which points to an incrementor function with 10 values added for each call. You can call this function multiple times to obtain the following results:
1 incrementByTen ()
2 // The returned value is 10
3 incrementByTen ()
4 // The returned value is 20
5 incrementByTen ()
6 // The returned value is 30
If you create another incrementor, it will reference its own independent runningtotal variable. In the following example, incrementbysevne captures a new runningtotal variable, which is irrelevant to the variable captured in incrementbyten:
1 let incrementBySeven = makeIncrementor (forIncrement: 7)
2 incrementBySeven ()
3 // The returned value is 7
4 incrementByTen ()
5 // The returned value is 40
NOTE: If your closure is assigned to a class instance, and the closure points to the instance or its members to capture the instance, you will create a strong reference ring between the closure and the instance. Swift uses the capture list to break this strong reference ring. For more information, see strong reference cycles for closures.
  Closure is a reference type In the above example, incrementbyseven and incrementbyten are constants, but the closure pointed to by these constants can still increase the captured variable values. This is because both functions and closures are reference types. Whether you assign a function or closure value to a constant or variable, you actually set the value of the constant or variable to reference the corresponding function or closure. In the above example, the reference of incrementbyten pointing to the closure is a constant, not the content of the closure. This also means that if you assign the closure value to two different constants/variables, both values will point to the same closure:
1 let alsoIncrementByTen = incrementByTen
2 alsoIncrementByTen ()
3 // The returned value is 50  
Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.