1. 程式人生 > >The Swift Programming Language

The Swift Programming Language

Closures

“Closures are self-contained blocks of functionality that can be passed around and used in your code. Closures in Swift are similar to blocks in C and Objective-C and to lambdas in other programming languages.”

閉包是可以傳遞並在你的程式碼中使用的具有某種功能的獨立的程式碼塊兒。Swift中的閉包類似於C和OC中的blocks並且和其他程式語言中的lambdas表示式類似。

“Closures can capture and store references to any constants and variables from the context in which they are defined. This is known as closing over those constants and variables, hence the name “closures”. Swift handles all of the memory management of capturing for you.”

閉包可以從他們被定義的上下文中捕獲以及儲存常量和變數的引用。這就是所說的關閉那些常量和變數,因此被叫做閉包。Swift為你處理所有捕獲的記憶體管理工作。

“NOTE


“Global and nested functions, as introduced in Functions, are actually special cases of closures. Closures take one of three forms:”

“Global functions are closures that have a name and do not capture any values.
Nested functions are closures that have a name and can capture values from their enclosing function.
Closure expressions are unnamed closures written in a lightweight syntax that can capture values from their surrounding context.”

“全域性和巢狀函式,就像在函式中所介紹的,實際上是一種特殊的閉包。閉包有以下三種形式”

“全域性函式是一種有名字到那時沒有捕獲任何值的閉包”

巢狀函式是一種有名字並且可以通過他們的巢狀功能來捕獲值的閉包

閉包表示式是一種通過輕量級語法寫出的未命名的閉包,它可以從他們的周圍的上下文中捕獲值

“Swift’s closure expressions have a clean, clear style, with optimizations that encourage brief, clutter-free syntax in common scenarios. These optimizations include:


Inferring parameter and return value types from context
Implicit returns from single-expression closures
Shorthand argument names
Trailing closure syntax”

Swift的閉包表示式有一種乾淨,明朗的風格,並且對於鼓勵在一般的場景中使用簡潔,clutter自由的語法做出了優化。這些優化包括:

從上下文中推斷引數和返回值型別

從單一表達式閉包返回隱式返回值

簡約引數名

結尾閉包語法

Closure Expressions

“Nested functions, as introduced in Nested Functions, are a convenient means of naming and defining self-contained blocks of code as part of a larger function. However, it is “sometimes useful to write shorter versions of function-like constructs without a full declaration and name. This is particularly true when you work with functions that take other functions as one or more of their arguments.

巢狀函式,就像在“巢狀函式”章節中介紹的,是一種方便的命名和定義字包含程式碼塊的方式。然而,對於書寫一些不需要完整宣告和命名的較短的類似於函式的結構體是很有用的。當你使用一種以其他函式作為他的一個或者更多引數的函式時,你會發現這確實是真的。

Closure expressions are a way to write inline closures in a brief, focused syntax. Closure expressions provide several syntax optimizations for writing closures in a shortened form without loss of clarity or intent. The closure expression examples below illustrate these optimizations by refining a single example of the sorted function over several iterations, each of which expresses the same functionality in a more succinct way.”

閉包表示式是一種以簡潔,緊湊的語法寫出內聯閉包的方式。閉包表示式提供了集中書寫閉包的語法優化,方式簡短,並且不丟失精確度與含義。以下閉包表示式的例子列舉了這些優化,一個排序函式通過幾次迭代得到了提煉,並且每次迭代都用一種更高效的方式表達了同樣的功能。

The Sorted Function

“Swift’s standard library provides a function called sorted, which sorts an array of values of a known type, based on the output of a sorting closure that you provide. Once it completes the sorting process, the sorted function returns a new array of the same type and size as the old one, with its elements in the correct sorted order. The original array is not modified by the sorted function.”

Swift的標準庫中提供了一種叫做排序的函式,他把一個已知型別的陣列中的值進行排序,基於你提供的排序閉包的輸出結果。一旦它完成了排序過程,排序函式就會返回一個與舊陣列包含元素型別相同大小相同的新陣列,並且元素有了正確的順序,而原始陣列並沒有被排序函式修改。

“The closure expression examples below use the sorted function to sort an array of String values in reverse alphabetical order. Here’s the initial array to be sorted:”

以下的閉包表示式舉例使用排序函式將一組字串型別的元素按逆序字母順序排序。以下是被排序的原始陣列:

“let names = ["Chris", "Alex", "Ewa", "Barry", "Daniella"]”

“The sorted function takes two arguments:


An array of values of a known type.
A closure that takes two arguments of the same type as the array’s contents, and returns a Bool value to say whether the first value should appear before or after the second value once the values are sorted. The sorting closure needs to return true if the first value should appear before the second value, and false otherwise.”

排序函式有兩個引數:

已知元素型別的一個數組

一個帶有兩個引數的閉包,這連個引數與陣列內容有相同的型別,並且值一旦被排序就會返回一個布林值以表明第一個值是應該在第二個值之前還是之後出現。如果第一個值應該在第二個值之前出現,這個排序閉包就需要返回true,否則的話返回false

“This example is sorting an array of String values, and so the sorting closure needs to be a function of type (String, String) -> Bool.”

這個列子是將一個字串陣列排序,所以排序閉包應該是一種函式型別(String,String)-> Bool

“One way to provide the sorting closure is to write a normal function of the correct type, and to pass it in as the sorted function’s second parameter:”

一種提供排序閉包的方法是寫一個型別正確的普通函式,並且將它傳給排序函式作為第二個引數

“func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = sorted(names, backwards)
// reversed is equal to ["Ewa", "Daniella", "Chris", "Barry", "Alex"]”


“If the first string (s1) is greater than the second string (s2), the backwards function will return true, indicating that s1 should appear before s2 in the sorted array. For characters in strings, “greater than” means “appears later in the alphabet than”. This means that the letter "B" is “greater than” the letter "A", and the string "Tom" is greater than the string "Tim". This gives a reverse alphabetical sort, with "Barry" being placed before "Alex", and so on.”

如果第一個字串s1比第二個字串要大,逆序函式將會返回true,表示在排序好的陣列中s1應該在s2之前出現。對於字串中的字元,“比...大”意味著“在字母表中後出現的”。這就意味著字母“B”比字母“A”要大,並且字串“Tom”比字串“Tim”要大。這就給了一個逆序的字元排序,因而“Barry”會被放過在“Alex”之前等等

“However, this is a rather long-winded way to write what is essentially a single-expression function (a > b). In this example, it would be preferable to write the sorting closure inline, using closure expression syntax.”

然而,這其實是一種相對冗餘的方式寫下了實際上一個較為簡單的表示式(a > b)。在這個例子中,將會更傾向於用內聯的方法,使用閉包表示式語法,寫排序閉包。

“Closure Expression Syntax
Closure expression syntax has the following general form:”

閉包表示式語法 ,閉包表示式語法有以下幾種形式

“{ (parameters) -> return type in
    statements
}”

“Closure expression syntax can use constant parameters, variable parameters, and inout parameters. Default values cannot be provided. Variadic parameters can be used if you name the variadic parameter and place it last in the parameter list. Tuples can also be used as parameter types and return types.”

閉包表示式語法合適使用常量引數,變數引數和輸入輸出引數。不能提供預設值。如果你命名了可變引數並且將它放在了引數列表中最後的位置它將會被使用。元祖也可以並用作引數型別和返回值型別。

“The example below shows a closure expression version of the backwards function from earlier:”

下面的例子顯示了較之之前的版本的一個逆序函式的閉包表示式版本。

“reversed = sorted(names, { (s1: String, s2: String) -> Bool in
    return s1 > s2
})”

“Note that the declaration of parameters and return type for this inline closure is identical to the declaration from the backwards function. In both cases, it is written as (s1: String, s2: String) -> Bool. However, for the inline closure expression, the parameters and return type are written inside the curly braces, not outside of them.”

注意這個內聯閉包的引數和返回值的生命和逆序函式的宣告是相同的。在這兩者中,它被寫作(s1:String,s2:String) -> Bool.然後,對於內聯閉包表示式,引數和返回值被寫在花括號裡面,而不是在外面。



“The start of the closure’s body is introduced by the in keyword. This keyword indicates that the definition of the closure’s parameters and return type has finished, and the body of the closure is about to begin.

閉包的主體部分以關鍵字in來引出。這個關鍵詞表明閉包的引數和返回值的定義已經結束,並且閉包的主體將要開始。
Because the body of the closure is so short, it can even be written on a single line:”
因為閉包的主體太短了,所以它可以被寫作簡單的一行

“reversed = sorted(names, { (s1: String, s2: String) -> Bool in return s1 > s2 } )”

“This illustrates that the overall call to the sorted function has remained the same. A pair of parentheses still wrap the entire set of arguments for the function. However, one of those arguments is now an inline closure.”

這個證明了排序函式的整體呼叫還保持原狀。一對圓括號仍然包含了這個函式的所有引數。然而,其中一個蠶食現在已經是內聯閉包了。

“Inferring Type From Context”

從上下文中推斷型別

“Because the sorting closure is passed as an argument to a function, Swift can infer the types of its parameters and the type of the value it returns from the type of the sorted function’s second parameter. This parameter is expecting a function of type (String, String) -> Bool. This means that the (String, String) and Bool types do not need to be written as part of the closure expression’s definition. Because all of the types can be inferred, the return arrow (->) and the parentheses around the names of the parameters can also be omitted:”

由於排序閉包被作為引數傳給函式,Swift可以從排序函式的第二個引數的型別中推斷他的引數的型別和它的返回值的型別。這個引數是函式型別的(String, String) -> Bool。這意味著(String,String)和布林型別不需要作為閉包表示式定義的一部分被寫出來。因為所有的型別都可以被推斷,箭頭->和圓括號也可以被省略。

“reversed = sorted(names, { s1, s2 in return s1 > s2 } )”

“It is always possible to infer the parameter types and return type when passing a closure to a function as an inline closure expression. As a result, you never need to write an inline closure in its fullest form when the closure is used as a function argument.
當傳遞一個閉包作為函式的內聯閉包表示式的時候,總是可以推斷引數型別和返回值型別的。因此,當閉包作為函式引數時你從不需要以完整形式寫出一個內聯閉包。

Nonetheless, you can still make the types explicit if you wish, and doing so is encouraged if it avoids ambiguity for readers of your code. In the case of the sorted function, the purpose of the closure is clear from the fact that sorting is taking place, and it is safe for a reader to assume that the closure is likely to be working with String values, because it is assisting with the sorting of an array of strings.”

雖然如此,如果你願意你仍然可以寫下精確的型別,並且如果他能避免你的程式碼含糊不清這樣的做法將會被鼓勵。在排序函式的例子中,相對於排序正在發生的事實閉包的目的更為清晰,並且如果使用者假定閉包可能通過字串型別使用那也將是安全的,因為他正在幫助一個字串陣列排序。

“Implicit Returns from Single-Expression Closures”
單一表達式閉包中的模糊返回值

“Single-expression closures can implicitly return the result of their single expression by omitting the return keyword from their declaration, as in this version of the previous example:”

單一表達式閉包可以通過從宣告中省略return關鍵字隱式地返回單一表達式的結果,就像之前的例子在下面的版本中的那樣:

“reversed = sorted(names, { s1, s2 in s1 > s2 } )”

“Here, the function type of the sorted function’s second argument makes it clear that a Bool value must be returned by the closure. Because the closure’s body contains a single expression (s1 > s2) that returns a Bool value, there is no ambiguity, and the return keyword can be omitted.”
在這兒,通過排序函式的第二個引數的函式型別可以更清楚的看到閉包必須返回一個Bool值。因為閉包的主體包含了表示式(s1 > s2)並返回一個Bool型別,沒有含糊不清,並且return關鍵字可以被省略。

Shorthand Argument Names

簡短的引數名

“Swift automatically provides shorthand argument names to inline closures, which can be used to refer to the values of the closure’s arguments by the names $0, $1, $2, and so on.”
Swift自動為內聯閉包提供了現成的引數名,通過使用$0,$1,$2等等來指向閉包的引數值。

“If you use these shorthand argument names within your closure expression, you can omit the closure’s argument list from its definition, and the number and type of the shorthand argument names will be inferred from the expected function type. The in keyword can also be omitted, because the closure expression is made up entirely of its body:”

如果你在你的閉包表示式中使用這些現成的引數名,你可以閉包的定義中省略了他的引數列表,現成的引數名字的數量和型別將會通過特定的函式型別來推斷出來。in關鍵字也可以被省略了,因為閉包表示式都是通過他的主體形成的

“reversed = sorted(names, { $0 > $1 } )”

“Here, $0 and $1 refer to the closure’s first and second String arguments.”

在這兒,$0和$1指的是閉包的第一個和第二個引數

Operator Functions

操作符函式

“There’s actually an even shorter way to write the closure expression above. Swift’s String type defines its string-specific implementation of the greater-than operator (>) as a function that has two parameters of type String, and returns a value of type Bool. This exactly matches the function type needed for the sorted function’s second parameter. Therefore, you can simply pass in the greater-than operator, and Swift will infer that you want to use its string-specific implementation:”

其實還有一種更加簡潔的方式來寫上述的閉包表示式。Swift的字串型別定義了關於字串對於比較運算子的實施實際上等同於有兩個字串引數的函式,並且返回Bool型別的值。這個精確地符合了排序函式中第二個引數所需要的函式型別。因此,你只需要傳入比較運算子,Swift就能推斷出你想要使用他的對應字串的特定的實施方法。

reversed = sorted(names, >)

Trailing Closures

尾隨閉包

“If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports:”


如果你需要將一個閉包表示式傳給一個函式作為函式最後一個引數並且閉包表示式很長,將它作為一個尾隨閉包來寫將會是很有用的。尾隨閉包就是一個閉包表示式但是寫在他所支援的函式呼叫的括號的外面或者之後的。

“func someFunctionThatTakesAClosure(closure: () -> ()) {
    // function body goes here
}
 
// here's how you call this function without using a trailing closure:
 
someFunctionThatTakesAClosure({
    // closure's body goes here
})
 
// here's how you call this function with a trailing closure instead:
 
someFunctionThatTakesAClosure() {
    // trailing closure's body goes here
}
”
“NOTE

If a closure expression is provided as the function’s only argument and you provide that expression as a trailing closure, you do not need to write a pair of parentheses () after the function’s name when you call the function.”

如果一個閉包表示式是某個函式唯一的引數並且你將其寫成尾隨閉包,那麼當你呼叫函式的時候不需要在函式名後面寫小括號

“The string-sorting closure from the Closure Expression Syntax section above can be written outside of the sorted function’s parentheses as a trailing closure:”

上述的字串排序閉包可以寫在函式的小括號外面作為尾隨閉包。

“reversed = sorted(names) { $0 > $1 }”

“Trailing closures are most useful when the closure is sufficiently long that it is not possible to write it inline on a single line. As an example, Swift’s Array type has a map(_:) method which takes a closure expression as its single argument. The closure is called once for each item in the array, and returns an alternative mapped value (possibly of some other type) for that item. The nature of the mapping and the type of the returned value is left up to the closure to specify.”

當一個閉包特別長不太容易以閉包表示式表達的時候尾隨閉包就會特別有效。例如,Swift的陣列型別有一個map方法,它有一個閉包表示式作為唯一的引數。陣列中的每個元素都會呼叫一次閉包,並且返回每一個元素的可選的對映值(可能是其他型別的)。而對映的實質和返回值的型別則是留給這個閉包具體去定義的。

“After applying the provided closure to each array element, the map(_:) method returns a new array containing all of the new mapped values, in the same order as their corresponding values in the original array.”

當陣列中的每一個元素都呼叫了閉包,map方法就返回一個包含所有新的對映值的陣列,並且以他們在原始陣列中對應的順序

“Here’s how you can use the map(_:) method with a trailing closure to convert an array of Int values into an array of String values. The array [16, 58, 510] is used to create the new array ["OneSix", "FiveEight", "FiveOneZero"]:”
下面就是你怎麼樣用一個尾隨閉包將一個整形陣列裝換成字串陣列。陣列[16,58,510]被用來建立新陣列["OneSix","FiveEight","FiveOneZero"];

“let digitNames = [
    0: "Zero", 1: "One", 2: "Two",   3: "Three", 4: "Four",
    5: "Five", 6: "Six", 7: "Seven", 8: "Eight", 9: "Nine"
]
let numbers = [16, 58, 510]”

“The code above creates a dictionary of mappings between the integer digits and English-language versions of their names. It also defines an array of integers, ready to be converted into strings.”

上述程式碼建立了一個在整形數字和他們的名字的英文版本之間相互對映的字典。它也定義個一個整型陣列,準備轉換成字典。

“You can now use the numbers array to create an array of String values, by passing a closure expression to the array’s map(_:) method as a trailing closure. Note that the call to numbers.map does not need to include any parentheses after map, because the map(_:) method has only one parameter, and that parameter is provided as a trailing closure:”

現在,你可以通過給陣列的map方法傳一個閉包作為尾隨閉包,將一個數字陣列裝換成字串陣列。注意呼叫numbers.map不需要在map後面新增任何的小括號,因為map方法只有一個引數,並且那個引數是一個尾隨閉包。

“let strings = numbers.map {
    (var number) -> String in
    var output = ""
    while number > 0 {
        output = digitNames[number % 10]! + output
        number /= 10
    }
    return output
}
// strings is inferred to be of type [String]
// its value is ["OneSix", "FiveEight", "FiveOneZero"]”

“The map(_:) method calls the closure expression once for each item in the array. You do not need to specify the type of the closure’s input parameter, number, because the type can be inferred from the values in the array to be mapped.”

陣列中的每個元素都會呼叫map函式的尾隨閉包。你不需要規定閉包中輸入的引數number的型別,因為型別可以從要被執行map操作的陣列中被推斷出來。

“In this example, the closure’s number parameter is defined as a variable parameter, as described in Constant and Variable Parameters, so that the parameter’s value can be modified within the closure body, rather than declaring a new local variable and assigning the passed number value to it. The closure expression also specifies a return type of String, to indicate the type that will be stored in the mapped output array.

在這個例子中,閉包的number引數被定義為一個可變的引數,就像常量和變數引數中描述的那樣,所以引數的值可以在閉包體內被修改,而不需要再宣告一個本地的變數再把值傳遞給它。閉包表示式也規定了字串型別的返回值,表明了map之後返回陣列的元素型別。

“The closure expression builds a string called output each time it is called. It calculates the last digit of number by using the remainder operator (number % 10), and uses this digit to look up an appropriate string in the digitNames dictionary. The closure can be used to create a string representation of any integer number greater than zero.”

每次呼叫閉包表示式,它都會建立一個叫做output的字串。它通過使用取餘運算計算出number的最後一位,然後通過這個數字在數字名稱字典中取出一個字串。閉包可以建立任何大於零的整數的字元型表示。

“NOTE

The call to the digitNames dictionary’s subscript is followed by an exclamation mark (!), because dictionary subscripts return an optional value to indicate that the dictionary lookup can fail if the key does not exist. In the example above, it is guaranteed that number % 10 will always be a valid subscript key for the digitNames dictionary, and so an exclamation mark is used to force-unwrap the String value stored in the subscript’s optional return value.”

字典下標後面跟著一個感嘆號,因為從字典中取值會返回一個可選型別,因為如果key不存在就可能查詢失敗。在上述例子中,能夠保證對於數字名稱字典來說number %10將會總是一個有效的key,因為感嘆號被用來強制解包出可選的返回值中儲存的字串。

“The string retrieved from the digitNames dictionary is added to the front of output, effectively building a string version of the number in reverse. (The expression number % 10 gives a value of 6 for 16, 8 for 58, and 0 for 510.)”

從數字名稱字典中獲取的字串被加在output的前面,有效的創造了逆序的數字的字串版本。(表示式number % 10會從16取得6,從58取得8,從510取得0)

“The number variable is then divided by 10. Because it is an integer, it is rounded down during the division, so 16 becomes 1, 58 becomes 5, and 510 becomes 51.”
變數number除以10.因為是整數,所以在除法中末尾被捨去,所以16變為1,58變為5,510變為51.


“The process is repeated until number /= 10 is equal to 0, at which point the output string is returned by the closure, and is added to the output array by the map function.


The use of trailing closure syntax in the example above neatly encapsulates the closure’s functionality immediately after the function that closure supports, without needing to wrap the entire closure within the map function’s outer parentheses.”

知道number /=10 等於0時重複運算才結束,此時字串被閉包返回,並被map函式加在ouput陣列中。

上例中尾隨閉包語法在函式後整潔封裝了具體的閉包功能,而不再需要將整個閉包包裹在map函式的括號內。

Capturing Values

捕獲值

“A closure can capture constants and variables from the surrounding context in which it is defined. The closure can then refer to and modify the values of those constants and variables from within its body, even if the original scope that defined the constants and variables no longer exists.”

閉包可以從它定義的上下文中捕獲常量和變數。閉包可以在它的主體內引用或者修改這些常量或者變數的值,即使定義常量和變數的原始範圍已經不存在了。

“In Swift, the simplest form of a closure that can capture values is a nested function, written within the body of another function. A nested function can capture any of its outer function’s arguments and can also capture any constants and variables defined within the outer function.”
在Swift中,閉包捕獲值的最簡單的形式是一個巢狀函式,即寫在另在一個函式體中的函式。一個巢狀函式可以捕獲外部函式的引數和外部函式定義的任何常量和變數。

“Here’s an example of a function called makeIncrementer, which contains a nested function called incrementer. The nested incrementer function captures two values, runningTotal and amount, from its surrounding context. After capturing these values, incrementer is returned by makeIncrementer as a closure that increments runningTotal by amount each time it is called.”

以下是一個叫做makeIncrementer的函式的例子,它包含了一個巢狀函式叫做incrementer.巢狀函式從它的上下文中捕獲了兩個值,runningTotal和amount。在捕獲了這些值之後,incremented被makeIncrementer作為閉包被返回,並且incrementer每次被呼叫都會在runningTotal上加上amount.

“func makeIncrementer(forIncrement amount: Int) -> () -> Int {
    var runningTotal = 0
    func incrementer() -> Int {
        runningTotal += amount
        return runningTotal
    }
    return incrementer
}
”

“The return type of makeIncrementer is () -> Int. This means that it returns a function, rather than a simple value. The function it returns has no parameters, and returns an Int value each time it is called. To learn how functions can return other functions, see Function Types as Return Types.”
makeIncrementer的返回值型別是()-> Int.這意味著它返回一個函式,而不是一個簡單的值。它返回的函式沒有引數,但在每次呼叫的時候返回一個int型別的值。想知道函式怎樣返回另外一個函式,請看 Function Types as Return Types

“The makeIncrementer function defines an integer variable called runningTotal, to store the current running total of the incrementer that will be returned. This variable is initialized with a value of 0.”

makeIncrementer函式定義了一個叫做runingTotal的整形變數,它是用來儲存將會被incrementer返回的當前的runningTotal的值。這個變數初始化為0.

“The makeIncrementer function has a single Int parameter with an external name of forIncrement, and a local name of amount. The argument value passed to this parameter specifies how much runningTotal should be incremented by each time the returned incrementer function is called.”

makeIncremenyer函式有一個整數型別的引數,外部引數名叫做forIncrement,內部引數名叫做amount.這個引數的引數值具體規定了incrementer每次被呼叫時runningTotal被加多少。

“makeIncrementer defines a nested function called incrementer, which performs the actual incrementing. This function simply adds amount to runningTotal, and returns the result.”

makeIncrementer定義了一個叫做incrementer的巢狀函式,而這個函式實際在執行著增量運算。這個函式就是在RunningTotal上加上amount,然後返回結果。

“When considered in isolation, the nested incrementer function might seem unusual:”

當隔離出這個巢狀的incrementer函式來看,可能看起來有點不正常

“func incrementer() -> Int {
    runningTotal += amount
    return runningTotal
}”

“The incrementer function doesn’t have any parameters, and yet it refers to runningTotal and amount from within its function body. It does this by capturing the existing values of runningTotal and amount from its surrounding function and using them within its own function body.”

incrementer函式沒有任何引數,但是他從他的函式體內引用了RunningTotal和amount。它從他的周圍函式體重捕獲了runningTotal和amount的值並在它自己的函式體重使用它們。

“Because it modifies the runningTotal variable each time it is called, incrementer captures a reference to the current runningTotal variable, and not just a copy of its initial value. Capturing a reference ensures that runningTotal does not disappear when the call to makeIncrementer ends, and ensures that runningTotal is available the next time the incrementer function is called..”

由於每次呼叫它都修改了runningTotal的值,incrementer捕獲了當前runningTotal變數的一個參考,而不是它的初始值的一個副本。捕獲引用保證了當makeIncrementer的呼叫結束後runningTotal不會消失,並且保證了runningTotal在下次incrementer被呼叫時仍然可用。

“However, because it does not modify amount, and amount is not mutated outside it, incrementer actually captures and stores a copy of the value stored in amount. This value is stored along with the new incrementer function.”

然而,因為它沒有修改amount,amount在它之外也沒有變化,incremented實際上捕獲並存儲了一份儲存在amount中的值的copy。這個值將伴隨這新的增量函式被儲存。

“NOTE

Swift determines what should be captured by reference and what should be copied by value. You don’t need to annotate amount or runningTotal to say that they can be used within the nested incrementer function. Swift also handles all memory management involved in disposing of runningTotal when it is no longer needed by the incrementer function.”

Swift規定了什麼應該通過引用捕獲而什麼是通過拷貝捕獲的。你不需要通過註釋來說amount或者runningTotal可以在巢狀函式incrementer內部使用。Swift也會處理當incrementer函式不再需要runningTotal時的所有的記憶體管理工作。

“Here’s an example of makeIncrementer in action:”
下面是一個makeIncrementer在實際中的一個例子

“let incrementByTen = makeIncrementer(forIncrement: 10)”

“This example sets a constant called incrementByTen to refer to an incrementer function that adds 10 to its runningTotal variable each time it is called. Calling the function multiple times shows this behavior in action:”

這個例子建立了一個叫做incrementByTen的例子來指向一個增量函式,這個增量函式每次被呼叫時RunningTotal都會加10.實際中多次呼叫這個函式的表現如下:
“incrementByTen()
// returns a value of 10
incrementByTen()
// returns a value of 20
incrementByTen()
// returns a value of 30”

“If you create a second incrementer, it will have its own stored reference to a new, separate runningTotal variable:”

如果你建立了第二個incrementer,它將會指向一個新的獨立的runningTotal變數。
“let incrementBySeven = makeIncrementer(forIncrement: 7)
incrementBySeven()
// returns a value of 7”

“Calling the original incrementer (incrementByTen) again continues to increment its own runningTotal variable, and does not affect the variable captured by incrementBySeven:”

再次呼叫原始的incrementer將會繼續在他自己的runningTotal變數上增加值,但是這並不影響incrementBySeven的值。
“incrementByTen()
// returns a value of 40”

“NOTE


If you assign a closure to a property of a class instance, and the closure captures that instance by referring to the instance or its members, you will create a strong reference cycle between the closure and the instance. Swift uses capture lists to break these strong reference cycles. For more information, see Strong Reference Cycles for Closures.”

如果你給一個類的例項指派了一個閉包屬性,那麼這個閉包將會通過引用例項或者他的成員來捕獲這個例項,你將會在閉包和他的例項中建立一個強引用迴圈。Swif使用引用列表打破這些強引用迴圈。更多資訊,請看Strong Reference Cycles for Closures

“Closures Are Reference Types”

“In the example above, incrementBySeven and incrementByTen are constants, but the closures these constants refer to are still able to increment the runningTotal variables that they have captured. This is because functions and closures are reference types.”

在上述例子中,incrementBySeven和incrementByTen都是常量,但是這些常量引用的閉包仍然能夠將他們捕獲的runningTotal變數進行增量。這是因為函式和閉包是引用型別的。

“Whenever you assign a function or a closure to a constant or a variable, you are actually setting that constant or variable to be a reference to the function or closure. In the example above, it is the choice of closure that incrementByTen refers to that is constant, and not the contents of the closure itself.”

無論您將函式/閉包賦值給一個常量還是變數,您實際上都是將常量/變數的值設定為對應函式/閉包的引用。 上面的例子中,incrementByTen指向閉包的引用是一個常量,而並非閉包內容本身。

“This also means that if you assign a closure to two different constants or variables, both of those constants or variables will refer to the same closure:”

這意味著如果你如果把一個閉包指派給了兩個不同的常量或者變數,這些常量或者變數將會引用同一個閉包。

“let alsoIncrementByTen = incrementByTen
alsoIncrementByTen()
// returns a value of 50”