Un "Closure" es una función anónima definida como bloque de código con parámetros, valor de retorno e instrucciones. Su sintaxis es:
{ (parameter1: InputType1, ...) -> ReturnType in
// statements
return x
}
La palabra clave in separa los tipos de datos de las instrucciones.
Se puede asignar un closure a una variable y ejecutarlo llamando el nombre de la variable, seguido de la lista de argumentos en paréntesis, con la diferencia que ya no van a tener etiquetas.
let sumar = { (first: Int, second: Int) -> Int in
first + second
}
let result = sumar(1, 2) // 3
Recibir un closure como parámetro en una función
Como puedo asignar un closure a una variable, también puedo pasarlo como argumento a una función. Para ello, el tipo del parámetro debe indicar los tipos de dato de los parámetros del closure y el tipo de dato de retorno. Por ejemplo:
let sumar = { (first: Int, second: Int) -> Int in
first + second
}
let multiplicar = { (first: Int, second: Int) -> Int in
first * second
}
func f(closure: (Int, Int) -> Int) {
let result = closure(1, 2)
print("El resultado es \(result)")
}
f(closure: sumar) // 3
f(closure: multiplicar) // 2
Para pasar un closure como argumento de una función no es necesaerio asignarlo a una variable, sino que se puede pasar directamente al llamado de la función.
func f(closure: (Int, Int) -> Int) {
let result = closure(1, 2)
print("El resultado es \(result)")
}
f(closure: { (first: Int, second: Int) -> Int in
first + second
}) // 3
f(closure: { (first: Int, second: Int) -> Int in
first * second
}) // 2
Inferencia de tipo
Así como Swift es capaz de inferir el tipo de un Int, Double o Bool también es capaz de hacerlo con un closure, siempre que tenga suficiente información contextual para hacerlo. Por ejemplo, en el ejemplo anterior, al pasar directamente un closure como argumento a una función, se puede omitir los tipos de los parámetros y valor de retorno, dado que el parámetro closure de la función ya había especificado el tipo (i.e. (Int, Int) -> Int).
Notar que:
- al quitar los tipos de datos de los parámetros del closure, ya no es necesario envolverlos entre paréntesis.
- La palabra clave
inmarca la división entre la lista de parámetros y las instrucciones.
func f(closure: (Int, Int) -> Int) {
let result = closure(1, 2)
print("El resultado es \(result)")
}
f(closure: { (first, second) in
first + second
}) // 3
f(closure: { first, second in
first * second
}) // 2
Closure remolcado ("Trailing Closure")
Cuando el último argumento de una función es un closure, se lo puede declarar después de llamar a la función. Cuando se pasa el closure de esta manera, pierde la etiqueta del argumento (e.g. closure:). Por ejemplo:
func f(closure: (Int, Int) -> Int) {
let result = closure(1, 2)
print("El resultado es \(result)")
}
f() { (first, second) in
first + second
} // 3
f() { first, second in
first * second
} // 2
Omitiendo los nombres de los parámetros
Además de poder inferir el tipo de los parámetros y valor de retorno, se puede omitir el nombre de los parámetros y, en lugar de ellos, referenciar cada parámetro por un índice numérico que empieza en 0, precedido del operador $ (e.g. $0, $1, $2, etc). Por ejemplo:
func f(closure: (Int, Int) -> Int) {
let result = closure(1, 2)
print("El resultado es \(result)")
}
f() { $0 + $1 } // 3
f() { $0 * $1 } // 2
Top comments (0)