O que é Extension Function em Kotlin?

Extension Functions permitem adicionar novas funções a classes existentes sem precisar herdar delas ou usar padrões como Decorator. Você estende o comportamento de qualquer classe — inclusive as que não são suas, como String, Int ou List.

É uma das funcionalidades mais elegantes do Kotlin e uma das que mais faz a galera se apaixonar pela linguagem.

Sintaxe básica

fun String.contarPalavras(): Int {
    return this.trim().split("\\s+".toRegex()).size
}

fun main() {
    val frase = "Kotlin é muito massa"
    println(frase.contarPalavras()) // 4
}

A função contarPalavras() agora pode ser chamada em qualquer String, como se fizesse parte da classe original. O this dentro da função se refere ao objeto em que ela foi chamada.

Extension em tipos numéricos

fun Double.formatarReais(): String {
    return "R$ ${"%.2f".format(this)}"
}

fun Int.ehPar(): Boolean = this % 2 == 0

fun main() {
    println(1599.90.formatarReais()) // R$ 1599.90
    println(42.ehPar())              // true
    println(7.ehPar())               // false
}

Extension em coleções

fun <T> List<T>.segundoOuNull(): T? {
    return if (this.size >= 2) this[1] else null
}

fun main() {
    val nomes = listOf("Ana", "Bruno", "Carlos")
    println(nomes.segundoOuNull()) // Bruno

    val vazia = emptyList<String>()
    println(vazia.segundoOuNull()) // null
}

Como funciona por trás

Na real, extension functions são resolvidas estaticamente. O compilador transforma a função numa função estática com o objeto como primeiro parâmetro. Isso significa que elas não suportam polimorfismo — é a classe declarada que conta, não a real.

open class Animal
class Cachorro : Animal()

fun Animal.som() = "..."
fun Cachorro.som() = "Au au!"

fun fazerSom(animal: Animal) = animal.som()

fun main() {
    println(fazerSom(Cachorro())) // "..." — usa o tipo declarado
}

Quando usar?

Use extension functions para adicionar utilidades a classes que você não controla, criar APIs mais fluentes e manter o código organizado. A biblioteca padrão do Kotlin é cheia delas.