Guía del Lenguaje
Funciones

Funciones

Define e invoca funciones, etiqueta sus argumentos, y usa sus valores de retorno.

Una función es un segmento auto-contenido de código que ejecuta una tarea específica. A una función le das un nombre que comunica lo que esta hace, y usas dicho nombre para llamar a la función y que esta ejecute su tarea, cuando sea necesario.

La sintaxis unificada de funciones de Swift es lo suficientemente flexible para expresar cualquier función —desde una sencilla, similar a las de C, sin nombres de parámetros, hasta un método complejo, del estilo de Objective-C, con nombres de argumentos y etiquetas para cada parámetro. Un parámetro puede proveer valores predeterminados que simplifican el llamado a una función, y pueden ser pasados como parámetros in-out, los cuales modifican una variable que les haya sido pasada una vez que la función haya completado su ejecución.

En Swift, cada función tiene un tipo, el cual se conforma por los tipos de los argumentos de la función y del valor de devolución de la misma. Este tipo, lo puedes usar como cualquier otro tipo en Swift, lo cual facilita pasar funciones como parámetros a otras funciones y devolver funciones desde otras funciones. Las funciones también pueden definirse dentro de otras funciones para encapsular funcionalidad útil dentro del ámbito de una función anidada.

Definición y llamado de una función

Al definir una función, puedes especificar —de manera opcional— uno o más valores tipados y con nombre que la función recibirá como valores de entrada; a estos valores se les conoce como parámetros. También puedes definir —opcionalmente— un tipo de valor que la función devolverá como valor de salida, una vez finalice su ejecución; a dicho valor se le conoce como valor de devolución.

Cada función tiene un nombre, el cual describe la tarea que la función ejecuta. Para usar una función, debes llamar a la función con su nombre y pasarle valores de entrada (conocidos como argumentos) que coincidan con el o los tipos de los parámetros de la función. Los argumentos de una función siempre deben proveerse en el mismo orden de la lista de parámetros de la función.

La función del siguiente ejemplo se llama saludar(persona), ya que eso es lo que esta hace, toma el nombre de una persona como entrada y devuelve un saludo para esta persona. Para hacer esto, defines un parámetro de entrada, un valor de tipo String llamado persona, y un valor de devolución —de tipo String— llamado saludo, el cual contiene un saludo para la persona:

func saludar(persona: String) -> String {
    let saludo = "¡Hola, " + persona + "!"
 
    return saludo
}

Toda esta información va dentro de la definición de una función, la cual va precedida por la palabra clave func. Para indicar el tipo de devolución de una función, utiliza la flecha de devolución (->) —un guión seguido de un signo mayor que—, seguida por el nombre del tipo de devolución.

La definición describe lo que la función hace, lo que espera recibir, y lo que devuelve al ejecutarse. La definición también facilita que la función pueda ser llamada desde cualquier lugar de tu código, evitando ambigüedades.

print(saludar(persona: "Ana"))
// Imprime "¡Hola, Ana!"
print(saludar(persona: "Pedro"))
// Imprime "¡Hola, Pedro!"

Para llamar a la función saludar(persona:), le pasas un valor de tipo String luego de la etiqueta del argumento persona, así: saludar(persona: "Ana"). Dado que la función devuelve una cadena, saludar(persona:) puede serle pasada a una llamada a la función print(_:separator:terminator:) para imprimir dicha cadena y ver su valor de devolución, como se ve en el ejemplo anterior.

El cuerpo de la función saludar(persona) empieza con la definición de una nueva constante —de tipo String— llamada saludo, a la que le es asignado un saludo de bienvenida sencillo. Luego, este saludo es devuelto por la función mediante la palabra clave return. En la línea de código que pone return saludo, la función finaliza su ejecución y devuelve el valor que saludo tenga en su momento.

Puedes llamar a la función saludar(persona) múltiples veces con distintos valores de entrada. En el ejemplo anterior, se aprecia lo que ocurre al llamar la función con los valores de entrada "Ana" y "Pedro". La función devuelve un saludo personalizado en cada caso.

Para acortar el cuerpo de esta función, puedes combinar la creación del mensaje y la instrucción de devolución en una sola línea:

func saludarOtraVez(persona: String) -> String {
    return "¡Hola nuevamente, " + persona + "!"
}
 
print(saludarOtraVez(persona: "Ana"))
// Imprime "¡Hola nuevamente, Ana!"

Parámetros de funciones y valores de devolución

Los parámetros y los valores de devolución de las funciones son extremadamente flexibles en Swift. Puedes definir cualquier función, desde una función utilitaria con un único parámetro anónimo hasta una función compleja con nombres de parámetros expresivos y diferentes opciones para dichos parámetros.

Funciones sin parámetros

Las funciones no requieren la definición de parámetros de entrada. Acá se tiene una función sin parámetros de entrada, la cual siempre devuelve el mismo mensaje String al ser llamada:

func decirHolaMundo() -> String {
    return "Hola, mundo."
}
 
print(decirHolaMundo())
// Imprime "Hola, mundo."

La definición de la función requiere de paréntesis aun cuando esta no toma ningún parámetro. El nombre de la función también va seguido de un par de paréntesis al momento de llamar a la función.

Funciones con múltiples parámetros

Las funciones pueden tener múltiples parámetros de entrada, los cuales se escriben dentro de los paréntesis de la función, separados por coma.

Esta función toma como entrada el nombre de una persona y un indicador de que ya se ha saludado o no a dicha persona, y devuelve un saludo apropiado para la persona:

func saludar(persona: String, fueSaludada: Bool) -> String {
    if fueSaludada {
        return saludarNuevamente(persona: persona)
    } else {
        return saludar(persona: persona)
    }
}
 
print(saludar(persona: "Cindy", fueSaludada: true))
// Imprime "¡Hola otra vez, Cindy!"

Para llamar a la función saludar(persona:fueSaludada:), le pasas un valor argumento de tipo String, con la etiqueta persona y un valor argumento de tipo Bool, con la etiqueta fueSaludada — en paréntesis y separados por coma. Observa que esta función es diferente a la función saludar(persona) que se mostró en una sección anterior. Aunque el nombre de ambas funciones empieza por saludar, la función saludar(persona:fueSaludada:) toma dos argumentos, mientras que la función saludar(persona:) solo toma uno.

Funciones sin valores de devolución

Las funciones no requieren definir un tipo de devolución. Aquí tenemos una versión de la función saludar(persona:), la cual imprime su propia cadena en lugar de devolverla:

func saludar(persona: String) {
    print("¡Hola, \(persona)!")
}
 
saludar(persona: "Jorge")
// Imprime "¡Hola, Jorge!"

Dado que no necesita devolver un valor, la definición de la función no incluye la flecha de devolución (->) o un tipo de devolución.

El valor de devolución de una función puede ignorarse al llamar a la función:

func imprimirYContar(cadena: String) -> Int {
    print(cadena)
 
    return cadena.count
}
 
func imprimirSinContar(cadena: String) {
    let _ = imprimirYContar(cadena: string)
}
 
imprimirYContar(cadena: "Hola, mundo")
// Imprime "Hola, mundo" y devuelve un valor de 12
 
imprimirSinContar(cadena: "Hola, mundo")
// Imprime "Hola, mundo", pero no devuelve un valor

La primera función —imprimirYContar(cadena:)— imprime una cadena y luego devuelve su número de caracteres como un Int. La segunda función — imprimirSinContar(cadena:)— llama a la primera función, pero ignora su valor de devolución. Cuando se llama a la segunda función, el mensaje es impreso por la primera función, pero no se utiliza su valor de devolución.

Funciones con múltiples valores de devolución

Es posible usar una tupla como el tipo de devolución de una función para devolver múltiples valores como parte de un solo valor de devolución compuesto.

El siguiente ejemplo define una función llamada minMax(array:), la cual encuentra los números menor y mayor en un array de valores Int:

func minMax(array: [Int]) -> (min: Int, max: Int) {
    var minimoActual = array[0]
    var maximoActual = array[0]
 
    for valor in array[1..<array.count] {
 
        if valor < minimoActual {
            minimoActual = valor
        } else if valor > maximoActual {
            maximoActual = valor
        }
 
    }
 
    return (minimoActual, maximoActual)
}

La función minMax(array:) devuelve una tupla que contiene dos valores Int. Estos valores se etiquetan min y max de manera que se puede acceder a ellos por su nombre al referenciar al valor de devolución de la función.

El cuerpo de la función minMax(array:) empieza asignando a dos variables llamadas minimoActual y maximoActual el valor del primer entero en el array. La función luego itera sobre los demás valores del array y verifica cada valor para determinar si es menor o mayor que los valores de minimoActual y maximoActual, respectivamente. Finalmente, los valores mínimo y máximo son devueltos como una tupla de dos valores Int.

Dado que a los valores que conforman la tupla se le asignaron nombres como parte del valor de devolución de la función, a estos se puede acceder mediante sintaxis de punto para obtener los valores mínimos y máximo que se hallaron:

let limites = minMax(array: [8, -6, 2, 109, 3, 71])
 
print("min es \(limites.min) y max es \(bounds.max)")
// Imprime "min es -6 y max es 109"

Observa que no hace falta nombrar a los miembros de la tupla en el momento en que la tupla es devuelta por la función ya que sus nombres han sido previamente especificados como parte del valor de devolución de la función.

Tuplas de devolución opcionales

Si el valor del tipo tupla de devolución de una función tiene el potencial de no contener ningún valor para toda la tupla, puedes devolver una tupla opcional para reflejar el hecho de que toda la tupla puede ser nil. Puedes indicar una tupla devuelta opcional al colocar un signo de interrogación (de cierre) después del paréntesis de cierre de la tupla, así (Int, Int)? o (String, Int, Bool)?.

La función minMax(array:) vista anteriormente devuelve una tupla que contiene dos valores Int. Sin embargo, la función no realiza ninguna verificación de seguridad sobre el array que recibe. Si el argumento array fuese un array vacío, la función minMax(array:) —tal como se define arriba— arrojaría un error de tiempo de ejecución al intentar acceder a array[0].

Para lidiar —de manera segura— con un array vacío, escribe la función minMax(array:) con una tupla opcional como valor a devolver y un valor a devolver de nil cuando el array esté vacío:

func minMax(array: [Int]) -> (min: Int, max: Int)? {
    if array.isEmpty { return nil }
 
    var minimoActual = array[0]
    var maximoActual = array[0]
 
    for valor in array[1..<array.count] {
 
        if valor < minimoActual {
            minimoActual = valor
        } else if valor > maximoActual {
            maximoActual = valor
        }
 
    }
 
    return (minimoActual, maximoActual)
}

Puedes utilizar encadenamiento opcional para verificar si la versión de la función minMax(array:) devuelve una tupla real o nil:

  if let limites = minMax(array: [8, -6, 2, 109, 3, 71]) {
    print("min es \(limites.min) y max es \(limites.max)")
}
// Imprime "min es -6 y max es 109"

Funciones con un valor de devolución implícito

Si todo el cuerpo de una función es una sola expresión, la función —implícitamente— devuelve dicha expresión. Por ejemplo, las dos siguientes funciones tienen el mismo comportamiento:

func saludo(para persona: String) -> String {
    "¡Hola, " + persona + "!"
}
 
print(saludo(para: "Andrea"))
// Imprime "¡Hola, Andrea!"
 
func otroSaludo(para persona: String) -> String {
    return "¡Hola, " + persona + "!"
}
 
print(otroSaludo(para: "Andrea"))
// Imprime "¡Hola, Andrea!"

Toda la definición de la función saludo(para:) es el mensaje de saludo que esta devuelve, lo que le permite usar esta forma abreviada. La función otroSaludo(para:) devuelve el mismo mensaje de saludo usando la palabra clave return como una función más extensa. Para cualquier función que escribas como una sola línea que devuelve algo, puedes omitir return.

Como verás en Declaración concisa de getters, los getters de propiedades también pueden omitir un return implícito.

Etiquetas de argumentos y nombres de parámetros de funciones

Cada parámetro de una función tiene tanto una etiqueta de argumento como un nombre de parámetro. La etiqueta de argumento se usa al invocar una función — cada argumento se escribe en la llamada de la función con su etiqueta de argumento precediéndole. El nombre del parámetro se utiliza en la implementación de la función. Por defecto, los parámetros utilizan su nombre de parámetro como su etiqueta de argumento.

func algunaFuncion(nombrePrimerParametro: Int, nombreSegundoParametro: Int) {
    // En el cuerpo de la función, nombrePrimerParametro y nombreSegundoParametro
    // se refieren a los valores argumento del primer y segundo parámetros.
}
 
algunaFuncion(nombrePrimerParametro: 1, nombreSegundoParametro: 2)

Todos los parámetros deben tener nombres únicos. Aunque es posible que múltiples parámetros tengan la misma etiqueta de argumento, tener etiquetas de argumentos únicas ayuda a que tu código sea más legible.

Especificando etiquetas de argumentos

Debes definir una etiqueta de argumento antes del nombre del parámetro, separados por un espacio:

func algunaFuncion(etiquetaArgumento nombreParametro: Int) {
    // En el cuerpo de la función, nombreParametro hace referencia al
    // valor argumento para dicho parámetro.
}

Acá vemos una variante de la función saludar(persona:), la cual toma el nombre y lugar de origen de una persona, y devuelve un saludo:

func saludar(persona: String, de lugarOrigen: String) -> String {
    return "¡Hola, \(persona)!  Es un placer que puedas visitarnos desde \(lugarOrigen)."
}
 
print(saludar(persona: "Luisa", from: "Cupertino"))
// Prints "¡Hola, Luisa! Es un placer que puedas visitarnos desde Cupertino."

El uso de etiquetas de argumento permiten que una función pueda ser llamada de manera expresiva, como una instrucción, mientras provee un cuerpo legible y de clara intención.

Omitiendo etiquetas de argumentos

Si no quieres una etiqueta de argumento para un parámetro, agrega un guión bajo (_) en lugar de una etiqueta de argumento explícita para dicho parámetro.

func algunaFuncion(_ primerNombreParametro: Int, segundoNombreParametro: Int) {
    // En el cuerpo de la función, primerNombreParametro y segundoNombreParametro
    // se refieren a los valores argumento para el primer y segundo parámetros.
}
 
algunaFuncion(1, segundoNombreParametro: 2)

Si un parámetro tiene una etiqueta de argumento, el argumento debe ir acompañado de la etiqueta al momento de llamar la función.

Valores de parámetros predeterminados

Puedes definir un valor predeterminado para cualquier parámetro de una función, asignando un valor al parámetro después del tipo del parámetro. Si un valor predeterminado ya se ha definido, puedes omitir el parámetro al invocar la función.

func algunaFuncion(parametroSinValorPredeterminado: Int, parametroConValorPredeterminado: Int = 12) {
    // Si omites el segundo argumento al invocar la función, entonces
    // el valor de parametroConValorPredeterminado será 12 dentro del
    // cuerpo de la función.
}
 
algunaFuncion(parametroSinValorPredeterminado: 3, parametroConValorPredeterminado: 6)
// parametroConValorPredeterminado es 6
 
algunaFuncion(parametroSinValorPredeterminado: 4)
// parametroConValorPredeterminado es 12

Coloca los parámetros que no tienen valor predeterminado al inicio de la lista de parámetros de una función, antes de los parámetros que sí tienen valores predeterminados. Los parámetros que no tienen valores predeterminados suelen ser más importantes para el significado de la función, por lo que al escribirlos primero, resulta más fácil identificar cuando la misma función está siendo llamada, independientemente de que se omita o no algún parámetro predeterminado.

Parámetros «variádicos»

Un parámetro «variádico» acepta cero o más valores de un tipo específico. Puedes usar parámetros «variádico» para especificar que al parámetro se le puede pasar un número variable de valores de entrada al momento de llamar la función. Escribe parámetros «variádicos» insertando tres puntos (...) después del tipo del parámetro:

Los valores que se le pasan a un parámetro «variádico» estarán disponibles dentro del cuerpo de la función como un array del tipo apropiado. Por ejemplo, un parámetro «variádico» con el nombre de numeros y de tipo Double..., estará disponible dentro del cuerpo de la función como un array constante, llamado numeros, de tipo [Double].

En el siguiente ejemplo, se calcula la media aritmética (también conocida como promedio) de una lista de números de cualquier tamaño:

func mediaAritmetica(_ numeros: Double...) -> Double {
    var total: Double = 0
 
    for numero in numeros {
        total += numero
    }
 
    return total / Double(numeros.count)
}
 
mediaAritmetica(1, 2, 3, 4, 5)
// Devuelve 3.0, que es la media aritmética de esos cinco números.
 
mediaAritmetica(3, 8.25, 18.75)
// Devuelve 10.0, que es la media aritmética de esos tres números.

Una función puede tener múltiples parámetros «variádicos». El primer parámetro que le siga a un parámetro «variádico» deberá tener una etiqueta de argumento. Una etiqueta de argumento elimina la ambigüedad sobre cuáles argumentos le son pasados al parámetro «variádico» y cuáles le son pasados a los parámetros que le siguen al «variádico».

Parámetros in-out

Los parámetros de las funciones son, por defecto, constantes. Intentar cambiar el valor del parámetro de una función dentro del cuerpo de la función resultará en un error de tiempo de compilación. Esto significa que no puedes cambiar el valor de un parámetro por accidente. Si quieres que una función modifique el valor de un parámetro y que los cambios persistan después de finalizada la ejecución de la función, define dicho parámetro como un parámetro in-out.

Para definir un parámetro in-out, agrega la palabra clave inout justo antes del tipo del parámetro. Un parámetro in-out tiene un valor que pasa a estar dentro de la función, es modificado por dicha función, y pasa a estar afuera de la función, para reemplazar al valor original. Para una discusión detallada sobre el comportamiento de los parámetros in-out y sobre las optimizaciones de compilador asociadas, consulta Parámetros in-out.

Solamente puedes pasar una variable como el argumento para un parámetro in-out. No es posible pasar una constante o un valor literal como argumento, ya que las constantes y los valores literales no pueden ser modificados. Al pasar una variable como argumento para un parámetro in-out, agrega el símbolo ampersand (&) justo antes del nombre de la variable, para indicar que esta puede ser modificada por la función.

Acá tenemos un ejemplo con una función llamada intercambiarDosEnteros(_:_:), la cual tiene dos parámetros in-out, enteros con nombres a y b.

func intercambiarDosEnteros(_ a: inout Int, _ b: inout Int) {
    let aTemporal = a
 
    a = b
    b = aTemporal
}

La función intercambiarDosEnteros(:_:_) simplemente intercambia los valores de a y b entre sí. La función ejecuta este cambio slmscenando el valor de a en una constante temporal llamada aTemporal, y luego asigna el valor de b a a, y asigna el valor de aTemporal a b.

Puedes invocar a la función intercambiarDosEnteros(_:_:) con dos valores de tipo Int para intercambiar sus valores. Nota que los nombres de algunEntero y otroEntero van precedidos de un ampersand al ser pasados como argumentos para la función intercambiarDosEnteros(_:_:):

var algunEntero = 3
var otroEntero = 107
 
intercambiarDosEnteros(&algunEntero, &otroEntero)
 
print("algunEntero es ahora \(algunEntero), y otroEntero es ahora \(otroEntero)")
// Imprime "algunEntero es ahora 107, y otroEntero es ahora 3"

El ejemplo anterior muestra que los valores originales de algunEntero y otroEntero fueron modificados por la función intercambiarDosEnteros(_:_:), aun cuando estas variables se definieron fuera de la función.

Tipos de funciones

Cada función tiene un tipo de función específico, el cual se compone del tipo de los parámetros y del tipo de devolución de la función.

Por ejemplo:

func sumarDosEnteros(_ a: Int, _ b: Int) -> Int {
    return a + b
}
 
func multiplicarDosEnteros(_ a: Int, _ b: Int) -> Int {
    return a * b
}

Este ejemplo define dos funciones matemáticas simples, llamadas sumarDosEnteros y multiplicarDosEnteros. Cada una de estas funciones toma dos valores Int y devuelve un valor Int, el cual es el resultado de llevar a cabo la operación matemática apropiada.

El tipo de estas dos funciones es (Int, Int) -> Int. Esto puede leerse como:

«Una función que tiene dos parámetros, ambos de tipo Int, y que devuelve un valor de tipo Int

Acá se tiene otro ejemplo, de una función sin parámetros ni valor de devolución:

func imprimirHolaMundo() {
    print("Hola, mundo")
}

El tipo de esta función es () -> Void, o una función que no tiene parámetros y que devuelve Void.

Usando tipos de funciones

Puedes usar tipos de funciones al igual que cualquier otro tipo en Swift. Por ejemplo, puedes definer una constante o una variable para que sea del tipo de una función y asignar una función apropiada para esa variable:

var funcionMatematica: (Int, Int) -> Int = sumarDosEnteros

Esto puede leerse como:

«Define una variable llamada funcionMatematica, la cual tiene un tipo de "una función que recibe dos valores de tipo Int y que devuelve un valor de tipo Int". Asigna a esta variable la función llamada sumarDosEnteros

La función sumarDosEnteros(_:_:) tiene el mismo tipo que la variable funcionMatematica, por lo que el verificador de tipos de Swift permite esta asignación.

Ahora puedes invocar a la función asignada mediante el nombre de funcionMatematica:

print("Resultado: \(funcionMatematica(2, 3))")
// Imprime "Resultado: 5"

Una función diferente con el mismo tipo le puede ser asignada a la misma variable, de la misma forma en que se hace con otros tipos:

funcionMatematica = multiplicarDosEnteros\n
print("Resultado: \(funcionMatematica(2, 3))")
// Imprime "Resultado: 6"

Al igual que con cualquier otro tipo, puedes dejar que Swift se encargue de inferir el tipo de una función cuando esta se asigna a una constante o variable:

let otraFuncionMatematica = sumarDosEnteros
// Se infiere que el tipo de otraFuncionMatematica es (Int, Int) -> Int

Tipos de funciones como tipos de parámetros

Puedes usar el tipo de una función —como (Int, Int) -> Int— como el tipo de parámetro para otra función. Esto te permitirá dejar algunos aspectos de la implementación de una función para que sean proporcionados por el llamador de la función al momento de invocarla.

Acá hay un ejemplo para imprimir los resultados de las funciones matemáticas previamente definidas:

func imprimirResultadoMatematico(_ funcionMatematica: (Int, Int) -> Int, _ a: Int, _ b: Int) {
    print("Resultado: \(funcionMatematica(a, b))")
}
 
imprimirResultadoMatematico(sumarDosEnteros, 3, 5)
// Imprime "Resultado: 8"

Este ejemplo define una función llamada imprimirResultadoMatematico(_:_:_:), la cual tiene tres parámetros. El primer parámetro se llama funcionMatematica y es de tipo (Int, Int) -> Int. Puedes pasar cualquier función de ese tipo como el argumento para este primer parámetro. Los segundo y tercer parámetros se llaman a y b, y son ambos de tipo Int. Estos son usados como los valores de entrada para la función matemática que se provea.

Al invocar imprimirResultadoMatematico(_:_:_:), se le pasa la función sumarDosEnteros(_:_:), y los valores enteros 3 y 5. Esta llama a la función proporcionada con los valores 3 y 5, e imprime el resultado: 8.

El rol de imprimirResultadoMatematico(_:_:_:) es el de imprimir el resultado de llamar a una función matemática del tipo apropiado. Lo que la implementación de esa función haga en realidad no es relevante; lo único que importa es que la función sea del tipo correcto. Esto le permite a imprimirResultadoMatematico(_:_:_:) delegar parte de su funcionalidad al llamador de la función de manera que conlleve seguridad de tipo.

Tipos de funciones como valores de devolución

Puedes utilizar el tipo de una función como el valor de devolución de otra función. Para esto, escribes el tipo de una función completo inmediatamente después de la flecha de devolución (->) de la función que devuelve.

El siguiente ejemplo define dos funciones simples, llamadas avanzar(_:) y regresar(_:). La función avanzar(_:) devuelve su valor de entrada incrementado en una unidad, y la función regresar(_:) devuelve su valor de entrada disminuido en una unidad. Ambas funciones tienen un tipo de (Int) -> Int:

func avanzar(_ input: Int) -> Int {
    return input + 1
}
 
func regresar(_ input: Int) -> Int {
    return input - 1
}

Acá tenemos una función llamada elegirFuncionDeMovimiento(debeRegresar:), cuyo tipo de devolución es (Int) -> Int. La función elegirFuncionDeMovimiento(debeRegresar:) devuelve la función avanzar(_:) o la función regresar(_:) basándose en un parámetro booleano llamado debeRegresar:

func elegirFuncionDeMovimiento(debeRegresar: Bool) -> (Int) -> Int {
    return debeRegresar ? regresar : avanzar
}

Ahora puedes usar la función elegirFuncionDeMovimiento(debeRegresar:) para obtener una función que se moverá en una dirección o la otra:

var valorActual = 3
let moverseHaciaCero = elegirFuncionDeMovimiento(debeRegresar: valorActual > 0)
// moverseHaciaCero ahora se refiere a la función regresar()

El ejemplo anterior determina si un movimiento positivo o negativo se necesita para mover una variable llamada valorActual progresivamente hacia cero. valorActual tiene un valor inicial de 3, por lo que valorActual > 0 devuelve true, haciendo que elegirFuncionDeMovimiento(debeRegresar:) devuelva la función regresar(_:). Una referencia a la función devuelta se almacena en una constante llamada moverseHaciaCero.

Ahora que moverseHaciaCero referencia la función correcta, puede usarse par contar hasta cero:

print("Contando hasta cero:")
// Contando hasta cero:
 
while valorActual != 0 {
    print("\(valorActual)...")
 
    valorActual = moverseHaciaCero(valorActual)
}
 
print("¡Cero!")
// 3...
// 2...
// 1...
// ¡Cero!

Funciones anidadas

Todas la funciones vistas hasta ahora en este capítulo han sido ejemplos de funciones globales, las cuales están definidas en un ambiente global. Sin embargo, también es posible definir funciones dentro del cuerpo de otras funciones, lo que se conoce como funciones anidadas.

Las funciones anidadas están ocultas del mundo exterior por defecto, pero aún pueden ser llamadas y usadas por las funciones que las contienen. Una función que contiene una o más funciones anidadas también puede devolver una de sus funciones anidadas para permitirle ser usada en otro ambiente.

Puedes reescribir la función elegirFuncionDeMovimiento(debeRegresar:) del ejemplo anterior para usar y devolver funciones anidadas:

func elegirFuncionDeMovimiento(debeRegresar: Bool) -> (Int) -> Int {
    func avanzar(input: Int) -> Int { return input + 1 }
    func regresar(input: Int) -> Int { return input - 1 }
 
    return debeRegresar ? regresar : avanzar
}
 
var valorActual = -4
let moverseHaciaCero = elegirFuncionDeMovimiento(debeRegresar: valorActual > 0)
// moverseHaciaCero ahora se refiere a la función anidada avanzar()
 
while valorActual != 0 {
    print("\(valorActual)... ")
 
    valorActual = moverseHaciaCero(valorActual)
}
 
print("!Cero!")
// -4...
// -3...
// -2...
// -1...
// !Cero!