Swift From Scratch Parámetros de función, tipos y anidamiento

En el artículo anterior, exploramos los conceptos básicos de las funciones en Swift. Las funciones, sin embargo, tienen mucho más que ofrecer. En este artículo, continuamos nuestra exploración de funciones y analizamos los parámetros de función, el anidamiento y los tipos..

1. Nombres de parámetros locales y externos

Nombres de parámetros

Revisemos uno de los ejemplos del artículo anterior. los PrintMessage (mensaje :) función define un parámetro, mensaje.

func printMessage (message: String) print (message)

Le asignamos un nombre, mensaje, al parámetro y usar este nombre cuando llamamos a la función.

printMessage (mensaje: "¡Hola mundo!")

Pero tenga en cuenta que también usamos el mismo nombre para hacer referencia al valor del parámetro en el cuerpo de la función.

func printMessage (message: String) print (message)

En Swift, un parámetro siempre tiene un local nombre del parámetro, y opcionalmente tiene un externo Nombre del parámetro. En el ejemplo, los nombres de parámetros locales y externos son idénticos.

Pautas API

A partir de Swift 3, el equipo de Swift ha definido un conjunto claro de directrices API. No voy a entrar en esas directrices en este tutorial, pero quiero señalar que la definición de la PrintMessage (mensaje :) La función se desvía de esas pautas. El nombre de la función contiene la palabra mensaje, y el parámetro también se nombra mensaje. En otras palabras, nos estamos repitiendo..

Sería más elegante si pudiéramos invocar el PrintMessage (mensaje :) funcionar sin el mensaje palabra clave. Esto es lo que tengo en mente..

printMessage ("Hola, mundo!")

Esto es posible, y está más en línea con las directrices de Swift API. Pero, ¿qué es diferente? La diferencia es fácil de detectar si echamos un vistazo a la definición de función actualizada. El ejemplo actualizado también revela más sobre la anatomía de las funciones en Swift.

func printMessage (_ message: String) print (message)

En una definición de función, cada parámetro está definido por un nombre de parámetro externo, un nombre de parámetro local, dos puntos y el tipo de parámetro. Si los nombres de los parámetros locales y externos son idénticos, solo escribimos el nombre del parámetro una vez. Es por eso que el primer ejemplo define un nombre de parámetro, mensaje.

Si no queremos asignar un nombre de parámetro externo a un parámetro, usamos el _, un guion bajo Esto le informa al compilador que el parámetro no tiene un nombre de parámetro externo, y eso significa que podemos omitir el nombre del parámetro cuando se invoca la función.

Nombres de parámetros externos

Objective-C es conocido por sus largos nombres de métodos. Si bien esto puede parecer torpe y poco elegante para los forasteros, hace que los métodos sean fáciles de entender y, si se eligen bien, muy descriptivos. El equipo Swift entendió esta ventaja e introdujo nombres de parámetros externos desde el primer día.

Cuando una función acepta varios parámetros, no siempre es obvio qué argumento corresponde a qué parámetro. Eche un vistazo al siguiente ejemplo para comprender mejor el problema. Observe que los parámetros no tienen un nombre de parámetro externo.

func power (_ a: Int, _ b: Int) -> Int var result = a para _ en 1 ... 

los poder(_:_:) función eleva el valor de una por el exponente segundo. Ambos parámetros son de tipo En t. Mientras que la mayoría de las personas pasarán intuitivamente el valor base como primer argumento y el exponente como segundo argumento, esto no queda claro en el tipo, nombre o firma de la función. Como vimos en el artículo anterior, invocar la función es sencillo.

potencia (2, 3)

Para evitar confusiones, podemos asignar nombres externos a los parámetros de una función. Luego podemos usar estos nombres externos cuando se llama a la función para indicar inequívocamente qué argumento corresponde a qué parámetro. Eche un vistazo al ejemplo actualizado a continuación..

Potencia func (base a: Int, exponente b: Int) -> Int var resultado = a para _ en 1 ... 

Tenga en cuenta que el cuerpo de la función no ha cambiado desde que los nombres locales no han cambiado. Sin embargo, cuando invocamos la función actualizada, la diferencia es clara y el resultado es menos confuso..

potencia (base: 2, exponente: 3)

Mientras que los tipos de ambas funciones son idénticos, (Int, Int) -> Int, Las funciones son diferentes. En otras palabras, la segunda función no es una redeclaración de la primera función. La sintaxis para invocar la segunda función puede recordarle Objective-C. Los argumentos no solo están claramente descritos, sino que la combinación de funciones y nombres de parámetros también describe el propósito de la función..

En algunos casos, desea utilizar el mismo nombre para el nombre del parámetro local y externo. Esto es posible, y no es necesario escribir el nombre del parámetro dos veces. En el siguiente ejemplo, usamos base y exponente como los nombres de los parámetros locales y externos.

Potencia de la función (base: Int, exponente: Int) -> Int var resultado = base para _ en 1 ... 

Al definir un nombre para cada parámetro, el nombre del parámetro sirve como el nombre local y externo del parámetro. Esto también significa que necesitamos actualizar el cuerpo de la función.

Es importante tener en cuenta que al proporcionar un nombre externo para un parámetro, debe usar ese nombre al invocar la función. Esto nos lleva a los valores por defecto..

Valores predeterminados

Cubrimos los valores predeterminados de los parámetros en el artículo anterior. Esta es la función que definimos en ese artículo..

func printDate (fecha: Fecha, formato: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date)

Qué sucede si no definimos un nombre de parámetro externo para el segundo parámetro, que tiene un valor predeterminado?

func printDate (fecha: Fecha, _ formato: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date))

Al compilador no parece importarle. ¿Pero es esto lo que queremos? Es mejor definir un nombre de parámetro externo a parámetros opcionales (parámetros con un valor predeterminado) para evitar confusiones y ambigüedades.

Observe que nos estamos repitiendo nuevamente en el ejemplo anterior. No es necesario definir un nombre de parámetro externo para el fecha parámetro. El siguiente ejemplo muestra lo que printDate (_: format :) La función se vería como si seguimos las directrices de Swift API.

func printDate (_ date: Date, format: String = "YY / MM / dd") -> String let dateFormatter = DateFormatter () dateFormatter.dateFormat = format return dateFormatter.string (from: date))

Ahora podemos invocar el formatDate (_: format :) funciona sin usar el fecha Etiqueta para el primer parámetro y con un formato de fecha opcional..

printDate (Date ()) printDate (Date (), format: "dd / MM / YY")

2. Parámetros y mutabilidad.

Repasemos el primer ejemplo de este tutorial, el imprimir mensaje (_ :) función. ¿Qué pasa si cambiamos el valor de la mensaje parámetro dentro del cuerpo de la función?

func printMessage (_ message: String) message = "Print: \ (message)" print (message)

El compilador no tarda mucho en comenzar a quejarse.

Los parámetros de una función son constantes. En otras palabras, si bien podemos acceder a los valores de los parámetros de la función, no podemos cambiar su valor. Para evitar esta limitación, declaramos una variable en el cuerpo de la función y usamos esa variable en su lugar.

func printMessage (_ message: String) var message = message message = "Print: \ (message)" print (mensaje)

3. Parámetros variables

Si bien el término puede sonar extraño al principio, los parámetros variables son comunes en la programación. Un parámetro variadic es un parámetro que acepta cero o más valores. Los valores deben ser del mismo tipo. El uso de parámetros variables en Swift es trivial, como lo ilustra el siguiente ejemplo.

func sum (_ args: Int…) -> Int var resultado = 0 para a en args resultado + = a retorno resultado suma (1, 2, 3, 4)

La sintaxis es fácil de entender. Para marcar un parámetro como variadic, agregue tres puntos al tipo de parámetro. En el cuerpo de la función, el parámetro variadic es accesible como una matriz. En el ejemplo anterior, args es una matriz de En t valores.

Debido a que Swift necesita saber qué argumentos corresponden a qué parámetros, se requiere que un parámetro variadic sea el último parámetro. También implica que una función puede tener como máximo un parámetro variadic.

Lo anterior también se aplica si una función tiene parámetros con valores predeterminados. El parámetro variadic siempre debe ser el último parámetro..

4. Parámetros de entrada-salida

Anteriormente en este tutorial, aprendiste que los parámetros de una función son constantes. Si desea pasar un valor a una función, modifíquelo en la función y vuelva a pasarlo fuera de la función, los parámetros de entrada y salida son lo que necesita.

El siguiente ejemplo muestra un ejemplo de cómo funcionan los parámetros de entrada y salida en Swift y cómo se ve la sintaxis.

func prefixString (_ string: inout String, con prefix: String) string = prefix + string

Definimos el primer parámetro como un parámetro de entrada-salida agregando el En fuera palabra clave. El segundo parámetro es un parámetro regular con un nombre externo de withString y un nombre local de prefijo. ¿Cómo invocamos esta función??

var input = "world!" prefixString (y entrada, con: "Hola")

Declaramos una variable., entrada, de tipo Cuerda y pasarlo a la prefixString (_: con :) función. El segundo parámetro es una cadena literal. Al invocar la función, el valor de la entrada variable se convierte Hola Mundo!. Tenga en cuenta que el primer argumento es prefijado con un ampersand, Y, para indicar que es un parámetro de entrada-salida.

No hace falta decir que las constantes y los literales no se pueden pasar como parámetros in-out. El compilador arroja un error cuando haces lo que se ilustra en los siguientes ejemplos.

Es evidente que los parámetros de entrada / salida no pueden tener valores predeterminados o pueden ser variados. Si olvida estos detalles, el compilador le recuerda amablemente con un error..

5. Anidación

En C y Objective-C, las funciones y los métodos no se pueden anidar. En Swift, sin embargo, las funciones anidadas son bastante comunes. Las funciones que vimos en este y en el artículo anterior son ejemplos de funciones globales, se definen en el ámbito global.

Cuando definimos una función dentro de una función global, nos referimos a esa función como una función anidada. Una función anidada tiene acceso a los valores definidos en su función envolvente. Eche un vistazo al siguiente ejemplo para entenderlo mejor..

func printMessage (_ message: String) let a = "hello world" func printHelloWorld () print (a)

Si bien las funciones de este ejemplo no son muy útiles, ilustran la idea de funciones anidadas y la captura de valores. los printHelloWorld () La función solo es accesible desde el interior del imprimir mensaje (_ :) función.

Como se ilustra en el ejemplo, la printHelloWorld () La función tiene acceso a la constante. una. El valor es capturado por la función anidada y, por lo tanto, es accesible desde dentro de esa función. Swift se encarga de capturar los valores, incluida la administración de la memoria de esos valores..

6. Tipos de funciones

Funciones como parámetros

En el artículo anterior, tratamos brevemente los tipos de funciones. Una función tiene un tipo particular, compuesto por los tipos de parámetros de la función y su tipo de retorno. los imprimir mensaje (_ :) La función, por ejemplo, es de tipo. (Cuerda) -> (). Recuérdalo () simboliza Vacío, que es equivalente a una tupla vacía.

Debido a que cada función tiene un tipo, es posible definir una función que acepte otra función como parámetro. El siguiente ejemplo muestra cómo funciona esto..

func printMessage (_ message: String) print (message) func printMessage (_ message: String, con la función: (String) -> ()) function (message) let myMessage = "Hello, world!" printMessage (myMessage, con: printMessage)

los PrintMessage (_: con :) La función acepta una cadena como su primer parámetro y una función de tipo. (Cuerda) -> () como su segundo parámetro. En el cuerpo de la función, la función que pasamos se invoca con el mensaje argumento.

El ejemplo también ilustra cómo podemos invocar el PrintMessage (_: con :) función. los mi mensaje constante se pasa como el primer argumento y la imprimir mensaje (_ :) Funciona como el segundo argumento. Cuan genial es eso?

Funciones como tipos de retorno

También es posible devolver una función desde una función. El siguiente ejemplo es un poco artificial, pero ilustra cómo se ve la sintaxis..

func compute (_ adición: Bool) -> (Int, Int) -> Int func add (_ a: Int, _ b: Int) -> Int return a + b func restra (_ a: Int, _ b: Int) -> Int return a - b si la adición return add else return restar deja computeFunction = compute (true) deja result = computeFunction (1, 2) print (result)

los calcular(_:) La función acepta un booleano y devuelve una función de tipo. (Int, Int) -> Int. los calcular(_:) La función contiene dos funciones anidadas que también son de tipo (Int, Int) -> Int, añadir(_:_:) y sustraer(_:_:).

los calcular(_:) función devuelve una referencia a cualquiera de los añadir(_:_:) o la sustraer(_:_:) función, basada en el valor de la adición parámetro.

El ejemplo también muestra cómo usar el calcular(_:) función. Almacenamos una referencia a la función que es devuelta por el calcular(_:) función en el computeFunction constante. Entonces invocamos la función almacenada en computeFunction, pasando en 1 y 2, almacenar el resultado en el resultado constante, e imprimir el valor de resultado En la salida estándar. El ejemplo puede parecer complejo, pero en realidad es fácil de entender si sabes lo que está pasando.

Conclusión

Ahora debe tener una buena comprensión de cómo funcionan las funciones en Swift y qué puede hacer con ellas. Las funciones son fundamentales para el lenguaje Swift, y las usarás ampliamente cuando trabajes con Swift.

En el siguiente artículo, nos sumergiremos primero en los cierres: una construcción poderosa que recuerda a los bloques en C y Objective-C, los cierres en JavaScript y las lambdas en Ruby.

Si desea aprender a usar Swift 3 para codificar aplicaciones del mundo real, consulte nuestro curso Crear aplicaciones de iOS con Swift 3. Ya sea que sea nuevo en el desarrollo de aplicaciones de iOS o desee cambiar de Objective-C, este El curso te ayudará a comenzar con Swift para el desarrollo de aplicaciones..