Swift Cierres
Los cierres (Closures) son bloques de código funcionales autónomos que se pueden usar en el código o pasar como parámetros para transferir valores.
Los cierres en Swift son similares a los bloques (blocks) en C y Objective-C, y a las funciones anónimas en algunos otros lenguajes de programación.
Las funciones globales y las funciones anidadas son en realidad cierres especiales.
Las formas de los cierres son:
| Funciones globales | Funciones anidadas | Expresiones de cierre |
| Tienen nombre pero no pueden capturar ningún valor. | Tienen nombre y también pueden capturar valores dentro de la función que los contiene. | Cierres sin nombre que utilizan una sintaxis ligera y pueden capturar valores según el contexto. |
Los cierres en Swift tienen muchas optimizaciones:
- Inferir tipos de parámetros y valores de retorno según el contexto
- Retorno implícito de cierres de expresión de una sola línea (es decir, si el cuerpo del cierre tiene solo una línea de código, se puede omitir return)
- Se pueden usar nombres de parámetros abreviados, como $0, $1 (comenzando desde 0, representan el i-ésimo parámetro...)
- Proporciona la sintaxis de cierre final (Trailing closure syntax)
- Un array de tipo conocido
- Una función de cierre, que debe recibir dos valores del mismo tipo que los elementos del array y devolver un valor booleano que indique si, al finalizar la ordenación, el primer parámetro aparece antes o después que el segundo parámetro. Si el valor del primer parámetro aparece antes que el valor del segundo parámetro, la función de cierre de ordenación debe devolvertrue, de lo contrario devuelvefalse。
Sintaxis
A continuación se define una sintaxis de cierre que recibe parámetros y devuelve un tipo especificado:
{(parameters) -> return type in
statements
}
Ejemplo
import Cocoa
let studname = { print("Swift 闭包实例。") }
studname()
El resultado de ejecutar el programa anterior es:
Swift 闭包实例。
La siguiente forma de cierre recibe dos parámetros y devuelve un valor booleano:
{(Int, Int) -> Bool in
Statement1
Statement 2
---
Statement n
}
Ejemplo
import Cocoa
let divide = {(val1: Int, val2: Int) -> Int in
return val1 / val2
}
let result = divide(200, 20)
print (result)
El resultado de ejecutar el programa anterior es:
10
Expresión de cierre
La expresión de cierre es una forma de construir cierres en línea utilizando una sintaxis concisa. Las expresiones de cierre proporcionan algunas optimizaciones de sintaxis que hacen que escribir cierres sea simple y claro.
Método sorted
La biblioteca estándar de Swift proporciona un método llamadosorted(by:)que ordena los valores de un array de tipo conocido según la función de cierre de ordenación que usted proporcione.
Una vez completada la ordenación, el método sorted(by:) devuelve un nuevo array del mismo tamaño que el array original, que contiene elementos del mismo tipo y ya correctamente ordenados. El array original no se modifica con el método sorted(by:).
El método sorted(by:) requiere dos parámetros:
Ejemplo
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)
El resultado de ejecutar el programa anterior es:
["S", "D", "BE", "AT", "AE"]
Si la primera cadena (s1) es mayor que la segunda cadena (s2), la función backwards devuelve true, lo que indica que en el nuevo array s1 debe aparecer antes que s2. Para los caracteres de una cadena, "mayor" significa "aparece más tarde según 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". Esto realizará una ordenación alfabética inversa, de modo que "AT" se colocará antes que "AE".
Abreviaturas de nombres de parámetros
Swift proporciona automáticamente la función de abreviación de nombres de parámetros para funciones en línea; puede llamar secuencialmente a los parámetros del cierre directamente mediante $0, $1, $2.
Ejemplo
import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
var reversed = names.sorted( by: { $0 > $1 } )
print(reversed)
$0 y $1 representan el primer y segundo parámetro de tipo String del cierre.
El resultado de ejecutar el programa anterior es:
["S", "D", "BE", "AT", "AE"]
Si utiliza abreviaturas de nombres de parámetros en una expresión de cierre, puede omitir su definición en la lista de parámetros del cierre, y los tipos correspondientes a las abreviaturas de nombres de parámetros se inferirán a través del tipo de función. La palabra clave in también se puede omitir.
Función de operador
En realidad, hay una forma aún más corta de escribir la expresión de cierre del ejemplo anterior.
El tipoStringde Swift define una implementación de cadena para el operador mayor que (>), que como función acepta dosStringparámetros de tipo y devuelveBoolun valor de tipo.sort(_:)Y esto coincide exactamente con el tipo de función requerido por el segundo parámetro del método. Por lo tanto, puede simplemente pasar un operador mayor que, y Swift puede inferir automáticamente que desea utilizar la implementación de la función de cadena del operador mayor que:
import Cocoa let names = ["AT", "AE", "D", "S", "BE"] var reversed = names.sorted(by: >) print(reversed)
El resultado de ejecutar el programa anterior es:
["S", "D", "BE", "AT", "AE"]
Cierre final
Un cierre final es una expresión de cierre escrita después de los paréntesis de la función, y la función admite llamarlo como último parámetro.
func someFunctionThatTakesAClosure(closure: () -> Void) {
// 函数体部分
}
// 以下是不使用尾随闭包进行函数调用
someFunctionThatTakesAClosure({
// 闭包主体部分
})
// 以下是使用尾随闭包进行函数调用
someFunctionThatTakesAClosure() {
// 闭包主体部分
}
Ejemplo
import Cocoa
let names = ["AT", "AE", "D", "S", "BE"]
//尾随闭包
var reversed = names.sorted() { $0 > $1 }
print(reversed)
El { $0 > $1} después de sort() es un cierre final.
El resultado de ejecutar el programa anterior es:
["S", "D", "BE", "AT", "AE"]
Nota: Si la función solo necesita un parámetro de expresión de cierre, cuando use un cierre final, incluso puede omitir
()omitirlo.reversed = names.sorted { $0 > $1 }
Capturar valores
Un cierre puede capturar constantes o variables en el contexto en el que se define.
Incluso si el ámbito original donde se definieron estas constantes y variables ya no existe, el cierre puede seguir refiriéndose a estos valores y modificándolos dentro del cuerpo de la función de cierre.
La forma más simple de cierre 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 de su función externa, así como las constantes y variables definidas.
Veamos este ejemplo:
func makeIncrementor(forIncrement amount: Int) -> () -> Int {
var runningTotal = 0
func incrementor() -> Int {
runningTotal += amount
return runningTotal
}
return incrementor
}
Una función makeIncrementor tiene un parámetro de tipo Int llamado amout, y tiene un nombre de parámetro externo forIncremet, lo que significa que al llamarla debe usar este nombre externo. El valor de retorno es una()-> Intfunción.
Dentro del cuerpo de la función, se declaran la variable runningTotal y una función incrementor.
La función incrementor no recibe ningún parámetro, pero dentro del cuerpo de la función accede a las variables runningTotal y amount. Esto se debe a que lo logra capturando las variables runningTotal y amount que ya existen en el cuerpo de la función que la contiene.
Dado que la variable amount no se modifica, incrementor en realidad captura y almacena una copia de dicha variable, y esa copia se almacena junto con incrementor.
Por lo tanto, cuando llamamos a esta función, se va acumulando:
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())
El resultado de ejecutar el programa anterior es:
10 20 30
Los cierres son tipos de referencia
En el ejemplo anterior, incrementByTen es una constante, pero el cierre al que apuntan estas constantes aún puede incrementar el valor de la variable capturada.
Esto se debe a que tanto las funciones como los cierres son tipos de referencia.
Ya sea que asigne la función/cierre a una constante o a una variable, en realidad está estableciendo el valor de la constante/variable como la referencia a la función/cierre correspondiente. En el ejemplo anterior, la referencia de incrementByTen al cierre es una constante, y no el contenido del cierre en sí.
Esto también significa que si asigna el cierre a dos constantes/variables diferentes, ambos valores apuntarán al mismo cierre:
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())
El resultado de ejecutar el programa anterior es:
50Otras extensiones