VISITAS:

martes, 11 de agosto de 2015

SWIFT (VI) FUNCIONES Y CLOSURES

Las funciones son algo típico en todos los lenguajes de programación clásicos. Los closures ya no lo son tanto, al menos, no son tan conocidos, aunque llevan existiendo muchos años en lenguajes tan conocidos como Javascript.

FUNCIONES EN SWIFT

Una función es un bloque de código que puede ser invocado por su nombre para ejecutar una determinada tarea. Puede recibir datos de entrada y puede retornar uno o más resultados. Cuando se define una función se especifican los parámetros de entrada y el tipo del valor retornado (si los hay). Cuando se invoca a una función se pasan datos como argumentos a la función y se puede recoger el resultado en una variable, por ejemplo. Nótese la sutil diferencia entre parámetros y argumentos.

Ejemplo de declaración de una función en swift:

    func suma(operando1 : Int, operando2 : Int) -> Int {
        return operando1 + operando2
    }

Llamada a una función:

    var a : Int = suma(3, 6)

Parámetros externos

En el ejemplo anterior, los nombres de los parámetros son internos a la función y no pueden utilizarse en la llamada, es decir, la llamada se basa únicamente en el orden de los parámetros. Pero a veces es mejor (o más claro) que en la llamada a la función se especifique también el nombre de los parámetros. Para ello se antepone el carácter # al nombre del parámetro:

    func resta(#minuendo : Int, #sustraendo : Int) -> Int {
        return minuendo - sustraendo
    }

Y la llamada:

    var resultado : Int = resta( minuendo : 5, sustraendo : 3)

Parámetros por defecto

Swift permite especificar un valor por defecto para un parámetro (o parámetros) que pudieran no especificarse en la llamada a función. Estos parámetros con valores por defecto deben situarse al final de la lista de parámetros en la declaración de la función. Cuando en un parámetro se especifica un valor por defecto, swift asume que ese parámetro es externo y permite su nombrado en la llamada (ver subapartado anterior "parámetros externos").

    func info(account : Int, owner : String  = "Unknown") -> String {
        return "Account: \(account), owner: \(owner)."
    }

Ejemplos de posibles llamadas a esta función:

    var s1 = info(26351)  --> Account 26351, owner: Unknown.
    var s2 = info(10005, owner : "John")  --> Account 10005, owner: John.

Retornando múltiples valores desde una función

Una función puede retornar múltiples valores de varias formas: retornando un objeto, retornando un array o diccionario, y por último, retornando una tupla. Veamos este último caso.

    func getUserInfo(id : String) -> (nombre : String, apellido : String, dni : Int) {
        // buscar información del usuario en BD por ejemplo
        return ("Juan", "López", "4747563-P")
    }

Llamada a esta función:

    var info = getUserInfo("A3625")
    println("\(info,nombre) \(info,apellido) - \(info.dni)")

Número variable de parámetros

En swift una función puede recibir un número variable de parámetros (puede ser cero). Esto se indica con ...
Dentro de la función los parámetros son un array.

    func printInfo(datos : String...) {
        for s in datos {
            println(s)
        }
    }

Llamada:

    printInfo("a", "b", "c", "d")

Parámetros variables

Los parámetros recibidos por una función son constantes (es como si tuvieran un let delante) y no se pueden modificar dentro de la función.
Si queremos modificar alguno de los parámetros de una función, debemos declararlo variable poniéndole var delante.

    func suma(var operando1 : Int, operando2 : Int) -> Int {
        operando1 += operando2
        return operando1
    }

Esto no significa que el argumento pasado a la función se vaya a modificar, simplemente que podemos cambiar el valor internamente en la función. Para que se modifique el argumento externo, tendremos que utilizar parámetros de entrada/salida, como se describe en el siguiente subapartado.

Parámetros de entrada/salida

Para que una función pueda modificar el valor de un argumento es necesario definir el parámetro correspondiente como inout:

    func duplica(inout valor : Int) {
        valor = 2 * valor
    }

En la llamada tenemos que anteponer el carácter & al argumento (el cual tiene que ser una variable obligatoriamente):

    var v : Int = 4;
    duplica(&v)
    println(v)   --> 8

CLOSURES EN SWIFT

Antes de entrar en las closures, introduzcamos el tema 

Las funciones como tipos de datos

Una característica muy interesante de swift (y de otros lenguajes de programación) es que las funciones pueden ser tratadas como tipos de datos. De esta forma, se puede por ejemplo definir una función y asignarla a una constante o variable:

    func kilometers2Miles(kilometers : Float) -> Float {
        return meters * 0.62137
    }
    let f = kilometers2Miles

Habiendo hecho esa asignación podemos invocar a la función a través de la constante:

    var result = f(100.0)

Lo interesante de esto es que cuando asignamos una función a una constante tenemos todas las capacidades de los tipos de datos. Concretamente, una función puede pasarse como argumento a otra función, o incluso ser retornada de una función.

El tipo de datos de la función lo definen los parámetros y el valor retornado. En el ejemplo anterior, la función recibe un parámetro Float y devuelve un valor Float, por tanto el tipo de esta función sería:

    (Float) -> Float

Por ejemplo, podemos definir una función que reciba otra función como parámetro:

    func invoke( theFunction : (Float) -> Float, value : Float) -> Float {
        return theFunction(value)
    }

Y podemos invocarla así:

    invoke(kilometers2Miles, 34.8)

Igualmente, podemos retornar una función:

    func getFunction() -> (Float) -> Float {
        return kilometers2Miles
    }

Expresiones closure

Una expresión closure es sencillamente un bloque de código. Las expresiones closure se pueden asignar a constantes o variables:

    let f = { println("Hola") }
    f()   --> Hola

Las expresiones closure también pueden recibir parámetros y devolver resultados. Por ejemplo:

    let m = { ( operando1 : Float, operando2 : Float) -> Float in return operando1 * operando2 }
    let v = m(20, 34.2)

La sintaxis es parecida a la de una función, pero no tiene nombre, todo va entre llaves y se utiliza la palabra reservada in para indicar el comienzo del código. De hecho, las funciones swift son expresiones closure con nombre.

Closures

Un closure es un bloque de código (una función o una expresión closure) junto con una o más variables que existen en el contexto de ese bloque de código. Por ejemplo:

    func externa() -> () -> Int {
        var contador = 0
        func interna() -> Int {
            contador += 1
            return contador
        }
        return interna
    }

    let miClosure = externa()
    let resultado = miClosure()

En este ejemplo, la función externa retorna una función interna. Realmente retorna un closure, ya que retorna la función interna más la variable contador, que está declarada en el scope de la función interna. De hecho, cada vez que se llama a miClosure() se va incrementando el contador.












1 comentario: