Menu
Coddy logo textTech

Funções de extensão

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 30 de 57.

Uma função de extensão adiciona uma função a um tipo existente sem alterar o código-fonte do tipo. Seu nome é escrito após o tipo receptor e, dentro dela, this se refere ao receptor, que também pode ser omitido:

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() })

Saída:

HELLO!
false
2

As extensões também funcionam em suas próprias classes, e as propriedades de extensão adicionam propriedades computadas. Uma extensão não pode adicionar estado armazenado e só pode acessar os membros públicos de seu 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())

Saída:

100.0 C is 212.0 F

As extensões são resolvidas estaticamente: o tipo declarado da expressão determina a extensão quando o programa é compilado, não a classe do objeto. Essa é a principal diferença em relação a um membro 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())

Saída:

circle member
shape extension

Quando a classe já tem um membro com a mesma assinatura, o membro sempre vence. Use membros para comportamentos que pertencem ao tipo e podem ser sobrescritos; use extensões para auxiliares adicionados externamente, como formatação para uma classe que não é sua:

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())

Saída:

member greet
extension wave
challenge icon

Desafio

Fácil

Money(cents) é fornecido em Money.kt. Escreva extensões para ele em MoneyExtensions.kt: as propriedades de extensão Int.dollars e Int.cents, que transformam um número em Money (12.dollars corresponde a 1200 centavos), Money.format(), que retorna $12.50 (ou -$3.05 para valores negativos), List<Money>.total(), que retorna a soma como Money, e Money.split(parts), que divide em parts valores que diferem em no máximo um centavo, com os maiores primeiro.

O código fornecido lê linhas 12 dollars ou 50 cents e uma última linha com o número de partes. Ele imprime cada valor, total: $12.50 e split 3: $4.17 $4.17 $4.16.

Seu código deve ficar em MoneyExtensions.kt e Money.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o 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 iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin