Lambdas En Kotlin

En este tutorial te mostraremos como declarar lambdas en Kotlin para definir funciones que sean pasadas como argumentos de otras.

Sintaxis De Lambdas En Kotlin

Una función lambda es un literal de función que puede ser usado como expresión. Esto quiere decir, una función que no está ligada a un identificador y que puedes usar como valor.

Por ejemplo, si tenemos la función f(s) = s + 2, en Kotlin podemos expresarla como una declaración de función separada, así:

fun sumarDos(s: Int) = s + 2

Al ser reescrita como lambda, tendrías lo siguiente:

{s:Int -> s + 2}

Definir la función de esta forma te permitirá usarla como un valor en diferentes situaciones, como pasarla como argumento de una función o almacenarla en una variable.

La sintaxis de un literal lambda va al interior de dos llaves {}. Sus componentes son:

  • Lista de parámetros — Cada parámetro es una declaración de variable, aunque esta lista es opcional
  • Operador de flecha -> — Se omite si no usas lista de parámetros
  • Cuerpo del lambda — Son las sentencias que van luego del operador de flecha
Sintaxis De Expresiones Lambda En Kotlin

La anterior sintaxis de la imagen se puede leer como «para cada par de s y t corresponde el valor 2*(s+t)«.

Lambda Como Argumento

Tratar a la funciones como pequeñas piezas de código con lambdas, te permite la flexibilidad de pasar funciones como argumentos de otras funciones (funciones de orden superior).

Por ejemplo:

Supón que se te presenta el problema de contar la cantidad de caracteres 'e' dentro de "develou.com".

La solución más común sin refactorizar, sería recorrer en un bucle for la cadena, con un condicional en su interior.

Sin embargo existe la función CharSequence.count(), a la cual podemos pasarle un lambda que represente el predicado propuesto en nuestro problema.

fun main() {
    val eCount = "develou.com".count({ char:Char -> char == 'e' })
    print("Total 'e': $eCount")
}

El predicado char -> char == 'e' se podría leer como «al parámetro char corresponde su resultado de igualdad con ‘e‘».

La salida del programa será la cantidad que es evidente:

Total 'e': 2

Si vas a la implementación de count(), verás que invoca nuestro lambda en un ciclo for:

public inline fun CharSequence.count(predicate: (Char) -> Boolean): Int {
    var count = 0
    for (element in this) if (predicate(element)) ++count
    return count
}

El parámetro predicate es un parámetro de tipo función (Char) -> Boolean.

Al ejecutar predicate() dentro del for, se ejecutará element == 'e'en cada iteración. Si es true, entonces count incrementa su valor.

Por esta razón, la sintaxis de las funciones lambda no tiene nombre, ya que se generaliza su uso como expresión. Esto te evita declarar clases, crear sus instancias y pasarlas como argumentos.

Omitir Paréntesis De Función

Exploremos algunas variaciones de la sintaxis de las funciones lambda.

Si la expresión lambda es el el último argumento en la función, puedes escribir las llaves por fuera del paréntesis:

val eCount = "develou.com".count() { char:Char -> char == 'e' }

Y si los paréntesis están vacíos, entonces puedes omitirlos completamente:

val eCount = "develou.com".count { char:Char -> char == 'e' }

Omitir Tipo Del Parámetro

Si el contexto permite la inferencia de tipo del parámetro en la lambda, entonces puedes omitirlo del bloque.

En nuestro ejemplo, el compilador puede llegar a determinar que el parámetro char es Char por la comparación de igualdad, por lo que podemos omitirlo

val eCount = "develou.com".count { char -> char == 'e' }

El Identificador it

Cuando tu lambda usa un único argumento y no piensas cambiar su nombre por cuestiones de legibilidad, puedes usar el identificador it.

Esta variable se deduce implícitamente con el tipo inferido por el compilador y puedes referirte a ella como tu parámetro.

Por ejemplo, si cambias el parámetro explicito char por it tendrías:

val eCount = "develou.com".count { it == 'e' }

Lambdas Con Múltiples Líneas

Es posible escribir una lambda con varias líneas en su cuerpo. Solo pon las expresiones dentro del paréntesis normalmente. La última línea será el resultado del lambda.

Por ejemplo, expande el predicado para count() y antepón una línea donde imprimas cada carácter procesado:

fun main() {
    val eCount = "develou.com".count {
        println("Carácter $it")
        it == 'e'
    }
    print("Total 'e': $eCount")
}

La salida sería:

Carácter d
Carácter e
Carácter v
Carácter e
Carácter l
Carácter o
Carácter u
Carácter .
Carácter c
Carácter o
Carácter m
Total 'e': 2

Únete Al Discord De Develou

Si tienes problemas con el código de este tutorial, preguntas, recomendaciones o solo deseas discutir sobre desarrollo Android conmigo y otros desarrolladores, únete a la comunidad de Discord de Develou y siéntete libre de participar como gustes. ¡Te espero!