English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
In this article, you will learn what closures are, their syntax, and the types of closures in Swift through examples.
In the article on Swift functions, we created a function using the func keyword. However, Swift also has another special type of function called a closure, which can be defined without using the func keyword and function name.
Like functions, closures can accept parameters and return values. They also contain a set of statements that are executed after the call and can be assigned to variables as functions./Constants.
Closures in Swift are similar to those in C and Objective-C.-Code blocks in C and anonymous functions in other programming languages are quite similar.
Global functions and nested functions are actually special closures.
Die Formen der Klauen sind:
Globale Funktionen | Nestfunktionen | Klausexpression |
Benannte, die keine Werte einfangen können. | Benannte, die auch Werte aus der geschlossenen Funktion einfangen können. | Unbenannte Klauen, die eine leichte Syntax verwenden und Werte aus dem Kontextumfeld einfangen können. |
Swift hat viele Optimierungen für Klauen:
Typen der Parameter und Rückgabewerte werden auf Basis des Kontexts abgeleitet
aus einer Einzeiligen Ausdrucksklauen implicit zurückgeben (das bedeutet, dass der Closurekörper nur eine Zeile Code hat und return weglassen kann)
Man kann vereinfachte Parameternamen wie $0, $1(von 0 beginnend, was den i-ten Parameter bedeutet...)
bietet die Syntax für nachfolgende Klauen (Trailing closure syntax)
Nachstehend wird die Syntax für die Definition einer Closure gezeigt, die Parameter annimmt und einen spezifischen Typ zurückgibt:
{(parameters) -> return type in statements }
let simpleClosure = { print("Hello, World!") } simpleClosure()
The output of the above program is as follows:
Hello, World!
Nachstehend wird ein Closure-Format gezeigt, das zwei Parameter annimmt und einen Boolean-Wert zurückgibt:
{(Int, Int) -> Bool in Statement1 Statement 2 --- Statement n }
let simpleClosure:(String) -> (String) = { name in let greeting = "Hello, World! " + "Program" return greeting } let result = simpleClosure("Hello, World") print(result)
The output of the above program is as follows:
Hello, World! Program
Klausexpressionen sind eine Möglichkeit, Inline-Klauen mit einer einfachen Syntax zu erstellen. Klausexpressionen bieten einige Syntaxoptimierungen, die das Schreiben von Klauen einfacher und klarer machen.
Die Swift-Standardbibliothek bietet eine Methode namens sorted(by:) Methoden, sortiert nach dem von Ihnen bereitgestellten Sortierklauseffekt, sortieren die Werte des Arrays mit bekanntem Typ.
Nach Abschluss der Sortierung gibt das sorted(by:)-Verfahren ein neues Array zurück, das die gleiche Größe wie das ursprüngliche Array hat, die gleiche Typen umfasst und die Elemente korrekt sortiert sind. Das ursprüngliche Array wird nicht durch das sorted(by:)-Verfahren geändert.
Das sorted(by:)-Verfahren muss zwei Parameter übergeben:
Array mit bekanntem Typ
Klauseffunktion, die Klauseffunktion muss zwei Werte derselben Typen wie die Elemente des Arrays übergeben und gibt einen Boolean-Wert zurück, um anzuzeigen, ob der erste übergebene Parameter nach der Sortierung vor dem zweiten Parameter steht oder nach hinten. Wenn der Wert des ersten Parameters vor dem Wert des zweiten Parameters steht, muss die Sortierklauseffunktion true,反之返回 false。
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.sorted(by: backwards) print(reversed)
The output of the above program is as follows:
["S", "D", "BE", "AT", "AE"]
如果第一个字符串(s1)大于第二个字符串(s2),backwards函数返回true,表示在新的数组中s1应该出现在s2前。对于字符串中的字符来说,"大于" 表示 "按照字母顺序较晚出现"。这意味着字母"B"大于字母"A",字符串"S"大于字符串"D"。它将进行字母逆序排序,"AT"将会排在"AE"之前。
Swift 自动为内联函数提供了参数名称缩写功能,您可以直接通过$0,$1,2来顺序调用闭包的参数。
import Cocoa let names = ["AT", "AE", "D", "S", "BE"] var reversed = names.sorted(by: { $0 > $1 }) print(reversed)
$0和$1表示闭包中第一个和第二个String类型的参数。
The output of the above program is as follows:
["S", "D", "BE", "AT", "AE"]
如果你在闭包表达式中使用参数名称缩写,您可以在闭包参数列表中省略对其定义,并且对应参数名称缩写的类型会通过函数类型进行推断。in 关键字同样也可以被省略。
实际上还有一种更简短的方式来撰写上面实例中的闭包表达式。
Swift 的String
类型定义了关于大于号 (>
) 的字符串实现,其作为一个函数接受两个String
类型的参数并返回Bool
类型的值。
而这正好与sort(_)
方法的第二个参数需要的函数类型相匹配。
因此,您可以简单地传递一个大于号,Swift可以自动推断出您想使用大于号的字符串函数实现:
import Cocoa let names = ["AT", "AE", "D", "S", "BE"] var reversed = names.sorted(by: >) print(reversed)
The output of the above program is as follows:
["S", "D", "BE", "AT", "AE"]
尾随闭包是一种书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。
func someFunctionThatTakesAClosure(closure: () -> Void) { // 函数体部分 } // 以下是不使用尾随闭包进行函数调用的示例 someFunctionThatTakesAClosure({ // Klammernkörper ) // 以下是用尾随闭包进行函数调用的示例 someFunctionThatTakesAClosure() {}} // Klammernkörper }
import Cocoa let names = ["AT", "AE", "D", "S", "BE"] //Followender Schließungsausdruck var reversed = names.sorted() { $0 > $1 } print(reversed)
sort() nachfolgend { $0 > $1} als Followenden Schließungsausdruck verwenden.
The output of the above program is as follows:
["S", "D", "BE", "AT", "AE"]
Hinweis:
Wenn eine Funktion nur ein Argument eines Klammernausdrucks benötigt, können Sie den Schließungsausdruck beim Verwenden eines Followenden Schließungsausdrucks weglassen()
Weggelassen.
reversed = names.sorted { $0 > $1 }
Klammern können Konstanten oder Variablen in ihrem Definitionsumfeld erfassen.
Selbst wenn der ursprüngliche Bereich, in dem diese Konstanten und Variablen definiert wurden, nicht mehr existiert, können Klammern immer noch auf diese Werte innerhalb der Klammerfunktion verweisen und sie ändern.
Die einfachste Form eines Klammers in Swift ist die Nestfunktion, also eine Funktion, die innerhalb der Funktion einer anderen definiert ist.
Nestfunktionen können alle Parameter und definierten Konstanten und Variablen der äußeren Funktion erfassen.
Sehen Sie sich dieses Beispiel an:
func makeIncrementor(forIncrement amount: Int) -> () -> Int { var runningTotal = 0 func incrementor() -> Int { runningTotal += amount return runningTotal } return incrementor }
Eine Funktion makeIncrementor, die einen Int-Typen als Parameter amout hat und einen externen Parameternamen forIncremet hat, was bedeutet, dass Sie ihn beim Aufruf verwenden müssen. Der Rückgabewert ist ein()-> Int
der Funktion.
Innerhalb der Funktion wurden die Variablen runningTotal und die Funktion incrementor deklariert.
Die Funktion incrementor hat keine Parameter, aber sie kann innerhalb der Funktion auf die Variablen runningTotal und amount zugreifen. Dies wird durch das Erfassen der Variablen runningTotal und amount, die im umgebenden Funktion existieren, realisiert.
Da die Variable amount nicht geändert wurde, hat incrementor tatsächlich eine Kopie dieser Variable erfasst und gespeichert, und diese Kopie wird zusammen mit incrementor gespeichert.
Daher wird bei der Aufrufung dieser Funktion der Wert immer addiert:
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) // The returned value is10 print(incrementByTen()) // The returned value is20 print(incrementByTen()) // The returned value is30 print(incrementByTen())
The output of the above program is as follows:
10 20 30
Im obigen Beispiel ist incrementByTen ein Konstant, aber diese Konstanten können immer noch den Wert der gefangenen Variablen erhöhen.
Dies liegt daran, dass Funktionen und Klammern Referenztypen sind.
Unabhängig davon, ob Sie eine Funktion/Ob Sie eine Klammer einem Konstanten oder einer Variable zuweisen, Sie weisen tatsächlich immer ein Konstant auf/Der Wert der Variable wird auf den entsprechenden Wert der Funktion gesetzt/Referenz auf eine Klammer. Im obigen Beispiel ist die Referenz, die incrementByTen auf die Klammer verweist, ein Konstant, und nicht der Inhalt der Klammer selbst.
This also means that if you assign a closure to two different constants/Variables, both values will 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) // The returned value is10 incrementByTen() // The returned value is20 incrementByTen() // The returned value is30 incrementByTen() // The returned value is40 incrementByTen() let alsoIncrementByTen = incrementByTen // The returned value is also50 print(alsoIncrementByTen())
The output of the above program is as follows:
50