Menu
Coddy logo textTech

Funciones de extensión

Parte de la sección Programación orientada a objetos del Journey de Kotlin de Coddy. Lección 30 de 57.

Una función de extensión añade una función a un tipo existente sin cambiar el código fuente del tipo. Su nombre se escribe después del tipo receptor y, dentro de ella, this hace referencia al receptor, que también se puede omitir:

fun String.shout() = uppercase() + "!"
fun Int.isEven() = this % 2 == 0

Dentro de main:

println("hello".shout())
println(7.isEven())
println(listOf(1, 2, 3, 4).count { it.isEven() })

Salida:

HELLO!
false
2

Las extensiones también funcionan en tus propias clases, y las propiedades de extensión añaden propiedades calculadas. Una extensión no puede añadir estado almacenado y solo puede acceder a los miembros públicos de su receptor:

class Temperature(val celsius: Double)

val Temperature.fahrenheit: Double
    get() = celsius * 9 / 5 + 32

fun Temperature.describe() = "$celsius C is $fahrenheit F"

Dentro de main:

println(Temperature(100.0).describe())

Salida:

100.0 C is 212.0 F

Las extensiones se resuelven estáticamente: el tipo declarado de la expresión determina la extensión cuando se compila el programa, no la clase del objeto. Esta es la principal diferencia con un miembro sobrescrito:

open class Shape {
    open fun member() = "shape member"
}
class Circle : Shape() {
    override fun member() = "circle member"
}

fun Shape.ext() = "shape extension"
fun Circle.ext() = "circle extension"

Dentro de main:

val s: Shape = Circle()
println(s.member())
println(s.ext())

Salida:

circle member
shape extension

Cuando la clase ya tiene un miembro con la misma firma, el miembro siempre gana. Usa miembros para el comportamiento que pertenece al tipo y puede sobrescribirse; usa extensiones para los asistentes añadidos desde fuera, como el formato de una clase que no te pertenece:

class Robot {
    fun greet() = "member greet"
}

fun Robot.greet() = "extension greet"
fun Robot.wave() = "extension wave"

Dentro de main:

val r = Robot()
println(r.greet())
println(r.wave())

Salida:

member greet
extension wave
challenge icon

Desafío

Fácil

Money(cents) se proporciona en Money.kt. Escribe extensiones para él en MoneyExtensions.kt: las propiedades de extensión Int.dollars y Int.cents, que convierten un número en Money (12.dollars son 1200 centavos), Money.format(), que devuelve $12.50 (o -$3.05 para cantidades negativas), List<Money>.total(), que devuelve la suma como Money, y Money.split(parts), que divide en parts cantidades que difieren como máximo en un centavo, con las mayores primero.

El código proporcionado lee líneas 12 dollars o 50 cents y una última línea con el número de partes. Imprime cada cantidad, total: $12.50 y split 3: $4.17 $4.17 $4.16.

Tu código va en MoneyExtensions.kt y Money.kt. Main.kt contiene el código proporcionado de entrada/salida y no se puede editar.

Pruébalo tú mismo

fun main() {
    // Código de entrada/salida suministrado: déjalo tal como está
    val input = generateSequence(::readLine).toList()
    val amounts = input.dropLast(1).map { line ->
        val (n, unit) = line.split(" ")
        if (unit == "dollars") n.toInt().dollars else n.toInt().cents
    }
    for (m in amounts) println(m.format())
    val total = amounts.total()
    println("total: ${total.format()}")
    val parts = input.last().toInt()
    println("split $parts: " + total.split(parts).joinToString(" ") { it.format() })
}
quiz iconPonte a prueba

Esta lección incluye un breve cuestionario. Empieza la lección para responderlo y registrar tu progreso.

Todas las lecciones de Programación orientada a objetos

Practica por tu cuenta: Playground de Kotlin