Diferenciar las funciones de extensión en Kotlin
- Crear una función de extensión en Kotlin
- Use funciones Lambda con funciones de extensión en Kotlin
-
Usa la función de extensión
let()
en Kotlin -
Usa la función de extensión
also()
en Kotlin -
Use la función de extensión
apply()
en Kotlin -
Usa la función de extensión
takeIf()
en Kotlin -
Usa la función de extensión
takeUnless()
en Kotlin - Conclusión
En la programación orientada a objetos, aprendimos los conceptos de herencia, encapsulación, abstracción y polimorfismo, pero estos no son suficientes para estructurar nuestra aplicación de manera flexible, reutilizable y mantenible.
Los patrones de diseño, con la ayuda de los principios de diseño y los conceptos de programación orientada a objetos, acudieron al rescate para introducir soluciones a problemas de diseño comunes. Un patrón de diseño muy similar al que cubriremos en este tutorial es el patrón de diseño del decorador.
El patrón de diseño decorador nos permite agregar funcionalidad a nuestra aplicación sin extenderla desde otra clase. En Kotlin, podemos lograr la misma funcionalidad que los patrones de diseño mediante el uso de funciones de extensión de Kotlin.
Las funciones de extensión en Kotlin agregan funcionalidad a una clase sin extender desde otra clase o usar el patrón de diseño del decorador. Detrás de escena, las funciones de extensión pueden ser genéricas y pueden usar funciones lambda para realizar la funcionalidad que hemos mencionado.
En este tutorial, aprenderemos a profundizar en cada una de las funciones de extensión y daremos un ejemplo para cada una. Las funciones de extensión cubiertas en este artículo incluyen: apply()
, also()
, let()
, takeIf()
y takeUnless()
.
Crear una función de extensión en Kotlin
Para crear una función de extensión, defina el tipo al que desea agregar la funcionalidad, como Cadena, Número o una clase, y use el operador de punto para definir el método delegado de la funcionalidad. Defina el tipo de retorno de la función de extensión y finalmente implemente la lógica del método en la misma línea.
Vaya al editor de código Intellij y cree un nuevo proyecto llamado extension-exercise
. Debajo de src
, cree la estructura de carpetas com.extension
.
Cree un archivo Main.kt
en la carpeta extension
y pegue el siguiente código.
package com.extension
fun Number.isGreaterThanTen(): Boolean = this.toInt() > 10;
fun main() {
val num = 100;
println(num.isGreaterThanTen());
}
En el código anterior, hemos definido una función de extensión denominada isGreaterThanTen()
en el tipo Número que comprueba si un número es mayor que 10 y devuelve un valor booleano.
Si invoca cualquier variable de tipo número a partir de este punto, tendrá acceso al método isGreaterThanTen()
, como se muestra en el método main anterior.
Tenga en cuenta que un valor booleano de true
se registra en la consola cuando ejecuta el programa anterior.
true
Use funciones Lambda con funciones de extensión en Kotlin
Detrás de escena, una función lambda se puede definir como una interfaz que contiene solo un método. La función lambda se pasa de forma anónima a una función concreta sin especificar el nombre de la función y, a continuación, el tipo de devolución se define mediante el símbolo de flecha.
Cree otro archivo y mueva el código anterior al archivo. Copie y pegue el siguiente ejemplo en el archivo Main.kt
vacío.
package com.extension
fun Number.isGreaterThanTen(block: (Number) -> Boolean): Boolean = block(this);
fun main() {
val num = 100;
println(num.isGreaterThanTen { number ->
number.toInt() > 10
})
}
En el código anterior, hemos definido una función de extensión denominada isGreaterThanTen()
que acepta una función lambda como parámetro y devuelve un valor booleano.
La función lambda, a la que hemos denominado block
, acepta un parámetro de tipo Número y devuelve un valor booleano. Este valor booleano devuelto por la función lambda se delega a la función de extensión.
En comparación con el ejemplo anterior, definimos la lógica de la función de extensión después de invocar el isGreaterThanTen()
en cualquier variable de tipo Número dentro de la función principal.
Ejecute el código anterior y observe que tenemos el mismo resultado que el ejemplo anterior. La salida es como se muestra a continuación.
true
Usa la función de extensión let()
en Kotlin
Mueve el código anterior al nuevo archivo que creamos y pega el siguiente código en el archivo Main.kt
.
package com.extension
inline fun <T, R> T.let(block: (T) -> R): R = block(this);
fun main(){
val num = 10;
val result = num.let { number -> number.toString() }
println(result);
println(result::class.java.typeName);
}
La función let()
se define usando genéricos, lo que significa que puede usar cualquier tipo. El objeto que invoca la función let()
se pasa como parámetro de la función lambda.
La función lambda se define dentro de la función let()
y devuelve un objeto diferente al pasado como parámetro.
Dado que el valor devuelto por la función let()
es el mismo que la función devuelta por la función lambda, hemos delegado el valor devuelto por la función lambda a la función let()
.
En el método main, hemos definido una variable de tipo Número e invocado nuestra función de extensión para devolver una representación de cadena del número.
Luego registramos el valor devuelto y su tipo en la consola para verificar que la función de extensión funciona según lo requerido. Tenga en cuenta que el tipo pasado a la función de extensión fue un Número, pero el valor devuelto fue una Cadena, como se muestra a continuación.
10
java.lang.String
Usa la función de extensión also()
en Kotlin
Mueva el código anterior al nuevo archivo que creamos y pegue el siguiente código en el archivo vacío Main.kt
.
package com.extension
inline fun <T> T.also(block: (T) -> Unit): T {block(this); return this}
fun main(){
val num = 10;
num.also {i ->
println(i == 10)
}
}
El objeto que invoca la función de extensión also()
se pasa como parámetro de la función lambda. La función lambda se define como el argumento de la función de extensión y no devuelve ningún valor normalmente denotado por una Unidad
.
La función also()
devuelve la variable actual que está utilizando, que se delega a la función lambda para su posterior cálculo. En la función principal hemos definido una variable de tipo Número delegada a la función lambda para comprobar si el valor es igual a 10.
Ejecute el código y observe que devuelve un valor verdadero, como se muestra a continuación.
true
Use la función de extensión apply()
en Kotlin
Mueva el código anterior al nuevo archivo que creamos y pegue el siguiente código en el archivo vacío Main.kt
.
package com.extension
inline fun <T> T.apply(block: T.() -> Unit): T {block(); return this}
fun main(){
val num = 10;
num.apply {
println(toDouble());
}
}
El objeto que invoca la función de extensión apply()
se pasa como invocación de método de este objeto al parámetro de la función lambda. La función lambda no tiene valor de retorno.
La definición significa que no tenemos que usar un objeto de un tipo para invocar un método porque la función lambda maneja la funcionalidad. En ese caso, solo necesitamos llamar al método que necesitamos de un tipo.
En la función principal, hemos definido una variable de tipo Número, y utilizando el método apply()
, hemos convertido el Número en un Doble llamando al método toDouble()
. Tenga en cuenta que no se utilizó ninguna referencia a un objeto para llamar al método toDouble()
.
Ejecute el código anterior y tenga en cuenta que el valor registrado en la consola es Doble, como se muestra a continuación.
10.0
Usa la función de extensión takeIf()
en Kotlin
Mueva el código anterior al nuevo archivo que creamos y pegue el siguiente código en el archivo vacío Main.kt
.
package com.extension
inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null
fun main() {
val num = 10;
println(num.takeIf { i ->
i.plus(10) < 30
})
}
El objeto que invoca la función de extensión takeIf()
se pasa como parámetro de la función lambda. La función lambda se pasa como argumento de este método y devuelve un valor booleano.
La función de extensión devuelve el objeto que invoca solo cuando la condición de la expresión lambda se evalúa como verdadera. De lo contrario, devuelve un valor null
.
En la función principal hemos definido un valor de tipo Número que utiliza el takeIf()
para determinar si este número más 10 es menor que treinta. Si la condición se evalúa como verdadera, se devuelve el valor 10
; de lo contrario, se devuelve un valor null
.
Ejecute el código anterior y tenga en cuenta que la expresión lambda se evalúa como verdadera y se devuelve el valor 10
, como se muestra a continuación.
10
Usa la función de extensión takeUnless()
en Kotlin
Mueva el código anterior al nuevo archivo que creamos y copie y pegue el siguiente código en el archivo vacío Main.kt
.
package com.extension
inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null
fun main() {
val num = 10;
println(num.takeUnless { i ->
i.plus(10) < 30
})
}
El objeto que invoca la función de extensión takeUnless()
se pasa como parámetro de la función lambda. La función lambda se define en este método y devuelve un valor booleano.
La diferencia entre takeIf()
y takeUnless()
es que este ejemplo solo devuelve un valor cuando la expresión lambda se evalúa como falsa. Esto significa que el valor devuelto por la función de extensión es el inverso de la función booleana devuelta por la función lambda.
Dentro del método main, hemos definido el mismo ejemplo anterior, pero observa que este ejemplo devolverá null
porque la función lambda evalúa a true
, que se invierte a false
.
null
Conclusión
Este tutorial nos enseñó cómo agregar funcionalidad en Kotlin usando las funciones de extensión. Las funciones de extensión cubiertas incluyen: usar let()
, also()
, apply()
, takeIf()
y takeUnless()
.
Tenga en cuenta que estas funciones de extensión ya están definidas en la API de Kotlin y no es necesario que las defina como lo hemos hecho en este tutorial.
David is a back end developer with a major in computer science. He loves to solve problems using technology, learning new things, and making new friends. David is currently a technical writer who enjoys making hard concepts easier for other developers to understand and his work has been published on multiple sites.
LinkedIn GitHub