40 - Funciones de extensión

Otra de las características muy útil de Kotlin para los programadores es el concepto de las funciones de extensión.

Mediante las funciones de extensión Kotlin nos permite agregar otros métodos a una clase existente sin tener que heredar de la misma.

Con una serie de ejemplos quedará claro esta característica.

Problema 1

Agregar dos funciones a la clase String que permitan recuperar la primer mitad y la segunda mitad.

Proyecto158 - Principal.kt

fun String.mitadPrimera(): String {
    return this.substring(0..this.length/2-1)
}

fun String.segundaMitad(): String{
    return this.substring(this.length/2..this.length-1)
}

fun main(args: Array<String>) {
    val cadena1 = "Viento"
    println(cadena1.mitadPrimera())
    println(cadena1.segundaMitad())
}

Para definir una función de extensión a una clase solo debemos anteceder al nombre de la función a que clase estamos extendiendo:

fun String.mitadPrimera(): String {
    return this.substring(0..this.length/2-1)
}

Dentro de la función mediante la palabra clave this podemos acceder al objeto que llamó a dicha función (en nuestro ejemplo como llamamos a mitadPrimera mediante el objeto cadena1 tenemos acceso a la cadena "Viento")

Cuando llamamos a una función de extensión lo hacemos en forma idéntica a las otras funciones que tiene la clase:

    println(cadena1.mitadPrimera())

La segunda función retorna un String con la segunda mitad del String:

fun String.segundaMitad(): String{
    return this.substring(this.length/2..this.length-1)
}

Podemos definir funciones de extensión que sobrescriban funciones ya existentes en la clase, es decir podríamos en la clase String crear una función llamada capitalize() y definir una nueva funcionalidad.

Problema 2

Agregar una función a la clase IntArray que permitan imprimir todas sus componentes en una línea.

Proyecto159 - Principal.kt

fun IntArray.imprimir() {
    print("[")
    for(elemento in this) {
        print("$elemento ")
    }
    println("]");
}

fun main(args: Array<String>) {
    val arreglo1= IntArray(10, {it})
    arreglo1.imprimir()
}

Definimos una función de extensión llamada imprimir en la clase IntArray, en su algoritmo mediante un for imprimimos todas sus componentes:

fun IntArray.imprimir() {
    print("[")
    for(elemento in this) {
        print("$elemento ")
    }
    println("]");
}

En la main definimos un arreglo de tipo IntArray de 10 elemento y guardamos mediante una expresión lambda los valores de 0 al 9.

Como ahora la clase IntArray tiene una función que imprime todas sus componentes podemos llamar directamente al método imprimir de la clase IntArray:

fun main(args: Array<String>) {
    val arreglo1= IntArray(10, {it})
    arreglo1.imprimir()
}

Problemas propuestos

  • Agregar a la clase String un método imprimir que muestre todos los caracteres que tiene almacenado en una línea.
  • Codicar la función de extensión llamada "hasta" que debe extender la clase Int y tiene por objetivo mostrar desde el valor entero que almacena el objeto hasta el valor que llega como parámetro:
    fun Int.hasta(fin: Int) {
    
Solución
Proyecto160

fun String.imprimir() {
    println(this)
}

fun main(args: Array<String>) {
    "Hola Mundo".imprimir()
    val cadena1 = "Fin"
    cadena1.imprimir()
}




Proyecto161

fun Int.hasta(fin: Int) {
    for(valor in this..fin)
        print("$valor-")
    println()
}

fun main(args: Array<String>) {
    val v = 10
    v.hasta(100)
    5.hasta(10)
}