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

Swift闭包

En este artículo, aprenderás qué son los closures, su sintaxis y los tipos de closures en Swift mediante ejemplos.

En el artículo sobre funciones de Swift, creamos una función utilizando la palabra clave func. Sin embargo, en Swift también hay otro tipo especial de función llamado closure, que se puede definir sin usar la palabra clave func ni el nombre de la función.
Al igual que las funciones, los closures pueden aceptar parámetros y devolver valores. También contienen un conjunto de instrucciones que se ejecutan después de la llamada y pueden asignarse a variables como funciones./Constantes.

Los closures en Swift son comparables a C y Objective-C-Los bloques de código en C y las funciones anónimas en otros lenguajes de programación son bastante similares.

Las funciones globales y las funciones anidadas son básicamente closures especiales.

Las formas de closure son:

Funciones globalesFunciones anidadasexpresión de cierre
Closures con nombre pero que no pueden capturar ningún valor.Closures con nombre, también pueden capturar valores dentro de la función cerrada.Closures anónimas, que utilizan una sintaxis ligera, pueden capturar valores del entorno contextual.

Hay muchos aspectos optimizados de las closures en Swift:

  • se infiere el tipo de parámetro y el valor de retorno desde el contexto

  • se devuelve implícitamente desde un closure de una sola línea (es decir, el cuerpo del closure solo tiene una línea de código y se puede omitir return)

  • Se puede usar nombres de parámetros simplificados, como $0, $1(desde 0, que representa el i-ésimo parámetro...)

  • proporciona la sintaxis de cierre colocado al final (trailing closure syntax)

sintaxis

La siguiente definición de closure recibe parámetros y devuelve un tipo especificado:

{(parameters) -> return type in
   statements
}

Ejemplo en línea

let simpleClosure = {
    print("¡Hola, Mundo!")
}
simpleClosure()

以上程序执行输出结果为:

¡Hola, Mundo!

La siguiente forma de closure recibe dos parámetros y devuelve un valor booleano:

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

Ejemplo en línea

let simpleClosure:(String) -> (String) = { name in
    
    let greeting = "¡Hola, Mundo!" + "Program"
    return greeting
}
let result = simpleClosure("¡Hola, Mundo!")
print(result)

以上程序执行输出结果为:

¡Hola, Mundo! Program

expresión de cierre

La expresión de cierre es una forma de construir closures inline con una sintaxis concisa. La expresión de cierre proporciona algunas optimizaciones de sintaxis que facilitan la escritura de closures.

método sorted

La biblioteca estándar de Swift proporciona una función llamada sorted(by:) El método, según la función de cierre proporcionada para ordenar, ordenará los valores en el array de tipo conocido.

Después de ordenar, el método sorted(by:) devuelve un nuevo array del mismo tamaño que el array original, que contiene elementos del mismo tipo y correctamente ordenados. El array original no se modificará por el método sorted(by:)

El método sorted(by:) necesita recibir dos parámetros:

  • El array de tipo conocido

  • La función de cierre, esta función de cierre necesita recibir dos valores de tipo idéntico al tipo de los elementos del array, y devuelve un valor de tipo booleano para indicar si al finalizar el ordenamiento, el primer parámetro ingresado se encuentra antes o después del segundo parámetro. Si el valor del primer parámetro aparece antes del valor del segundo parámetro, la función de cierre de ordenamiento debe devolver truede lo contrario, devuelve false.

Ejemplo en línea

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
// Para proporcionar la funcionalidad de ordenación mediante una función común (o una función anidada), el tipo de función de la clausura debe ser (String, String) -> Bool.
func backwards(s1: String, s2: String) -> Bool {
    return s1 > s2
}
var reversed = names.sorted(by: backwards)
print(reversed)

以上程序执行输出结果为:

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

si la primera cadena (s1) es mayor que la segunda cadena (s2) y la función backwards devuelve true, lo que indica que s1debería aparecer en s2antes. Para los caracteres de una cadena, "mayor que" significa "aparece más tarde en el orden alfabético". Esto significa que la letra "B" es mayor que la letra "A", y la cadena "S" es mayor que la cadena "D". Se realizará un orden alfabético inverso, y "AT" se colocará antes de "AE".

abreviatura de nombres de parámetros

Swift proporciona automáticamente la funcionalidad de abreviatura de nombres de parámetros para las funciones en línea, y puede usar directamente $0, $1,2para llamar en secuencia a los parámetros de la clausura.

Ejemplo en línea

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: { $0 > $1 })
print(reversed)

$0 y $1representa los primeros y segundos parámetros de tipo String en la clausura.

以上程序执行输出结果为:

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

Si utiliza abreviaturas de nombres de parámetros en la expresión de clausura, puede omitir su definición en la lista de parámetros de la clausura y el tipo de la abreviatura del nombre del parámetro se infiere a través del tipo de función. La palabra clave in también se puede omitir.

funciones operadores

De hecho, hay una manera más corta de escribir la expresión de clausura en el ejemplo anterior.

SwiftStringLa definición del operador de comparación de mayor que (>) implementación de cadena como una función que acepta dosStringparámetros y devuelveBoolvalores del tipo. Y esto coincide consort(_)El segundo parámetro de la función necesita un tipo de función que coincida. Por lo tanto, puede simplemente pasar un signo mayor, y Swift puede inferir automáticamente que desea usar la implementación de la función de cadena de signo mayor:

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted(by: >)
print(reversed)

以上程序执行输出结果为:

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

Closures de cola

Una clausura de cola es una expresión de clausura escrita después de los paréntesis de una función, y el lenguaje de programación admite que se la llame como el último parámetro.

func someFunctionThatTakesAClosure(closure: () -> Void) {
    // Parte del cuerpo de la función
}
// A continuación se muestra cómo se realiza una llamada a la función sin utilizar una clausura de cola
someFunctionThatTakesAClosure({
    // Parte del cuerpo de la closure
)
// A continuación se muestra cómo se realiza una llamada a la función utilizando una clausura de cola
someFunctionThatTakesAClosure() {}}
  // Parte del cuerpo de la closure
}

Ejemplo en línea

import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
//Closures de cola
var reversed = names.sorted() { $0 > $1 }
print(reversed)

Después de sort() { $0 > $1} como closure de cola.

以上程序执行输出结果为:

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

Nota: Si la función solo necesita un parámetro de expresión de closure, incluso puede omitir los paréntesis cuando se utiliza una closure de cola.()Se omitió.

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

Valores capturados

La closure puede capturar constantes o variables en el contexto en el que se define.

Incluso si el ámbito original de definición de estas constantes y variables ya no existe, la closure puede referirse y modificar estos valores dentro de la función de closure.

La forma más simple de closure en Swift es la función anidada, es decir, una función definida dentro del cuerpo de otra función.

Las funciones anidadas pueden capturar todos los parámetros y constantes definidas en la función externa.

Ve este ejemplo:

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

Una función makeIncrementor que tiene un parámetro de tipo Int llamado amout, y un parámetro externo llamado forIncremet, lo que significa que debe usar este nombre externo al llamar. El valor de retorno es un()-> Intde la función.

En el cuerpo de la función, se declaran las variables runningTotal y una función incrementor.

La función incrementor no recibe ningún parámetro, pero accede a las variables runningTotal y amount dentro del cuerpo de la función. Esto se debe a que captura las variables runningTotal y amount que ya existen en el cuerpo de la función que la contiene.

Dado que no se modificó la variable amount, incrementor realmente captura y almacena una copia de esta variable, y esta copia se almacena junto con incrementor.

Por lo tanto, cuando llamamos a esta función, se acumulará:

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

以上程序执行输出结果为:

10
20
30

La closure es un tipo de referencia

En el ejemplo anterior, incrementByTen es una constante, pero estas constantes aún pueden aumentar el valor de las variables capturadas por la closure.

Esto se debe a que tanto las funciones como las closures son tipos de referencia.

No importa si asigna una función/Independientemente de si asigna una closure a una constante o a una variable, en realidad está asignando una constante/El valor de la variable se establece para la función correspondiente/Referencia de closure. En el ejemplo anterior, incrementByTen apunta a una referencia de closure que es una constante, no al contenido de la closure en sí.

这也意味着如果您将闭包赋值给了两个不同的常量/变量,两个值都会指向同一个闭包:

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

以上程序执行输出结果为:

50