English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Swift Closures

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 FunktionenNestfunktionenKlausexpression
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)

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
}

Online-Beispiel

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
}

Online-Beispiel

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

Klausexpression

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.

sorted-Methode

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

Online-Beispiel

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来顺序调用闭包的参数。

Online-Beispiel

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"]

Followender Schließungsausdruck

尾随闭包是一种书写在函数括号之后的闭包表达式,函数支持将其作为最后一个参数调用。

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // 函数体部分
}
// 以下是不使用尾随闭包进行函数调用的示例
someFunctionThatTakesAClosure({
    // Klammernkörper
)
// 以下是用尾随闭包进行函数调用的示例
someFunctionThatTakesAClosure() {}}
  // Klammernkörper
}

Online-Beispiel

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 }

Gefangene Werte

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()-> Intder 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

Klammern sind Referenztypen

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