Extension functions sao uma das features do Kotlin que mais uso no dia a dia. Elas permitem adicionar metodos a classes sem precisar herdar delas.
A sintaxe e simples. Voce escreve o nome da classe seguido de ponto e o nome da funcao:
fun String.isEmail(): Boolean {
return this.contains("@") && this.contains(".")
}
println("teste@email.com".isEmail()) // true
println("invalido".isEmail()) // false
Repare que this dentro da extension function se refere a instancia da String.
Para arquivos com multiplas extensions, crie um arquivo separado como StringExtensions.kt:
// StringExtensions.kt
fun String.limparEspacos(): String = this.trim().replace(Regex("\\s+"), " ")
fun String.truncar(max: Int): String = if (length <= max) this else substring(0, max) + "..."
Uso:
val texto = " texto com espacos "
println(texto.limparEspacos()) // "texto com espacos"
println("Mensagem muito longa aqui".truncar(10)) // "Mensagem m..."
Extension functions tambem funcionam com generics. Um exemplo pratico para listas:
fun <T> List<T>.segundoOuNull(): T? {
return if (size >= 2) this[1] else null
}
val lista = listOf("a", "b", "c")
println(lista.segundoOuNull()) // "b"
println(listOf("unico").segundoOuNull()) // null
Um padrao util e criar extensions para Android ou Spring que simplificam chamadas repetitivas:
fun RecyclerView.setupAdapter(items: List<Any>, layoutId: Int) {
adapter = GenericAdapter(items, layoutId)
}
fun SharedPreferences.editar(block: SharedPreferences.Editor.() -> Unit) {
val editor = edit()
editor.block()
editor.apply()
}
preferences.editar {
putString("nome", "Joao")
putInt("idade", 30)
}
Nesse ultimo exemplo, block e uma lambda com receiver. O SharedPreferences.Editor vira o this dentro do bloco, e voce chama putString diretamente.
Uma limitacao: extension functions nao sobrescrevem metodos existentes. Se a classe ja tem um metodo com a mesma assinatura, o metodo da classe vence:
class Pessoa(val nome: String)
fun Pessoa.toString(): String = "Pessoa: $nome"
val p = Pessoa("Joao")
println(p.toString()) // Exibe o toString() original da data class, nao a extension
Extension functions sao resolvidas estaticamente, no momento da compilacao. Elas nao sao virtuais. Isso significa que o tipo da variavel decide qual funcao chama:
open class Animal
class Cachorro : Animal()
fun Animal.falar() = "som generico"
fun Cachorro.falar() = "latido"
val animal: Animal = Cachorro()
println(animal.falar()) // "som generico" (tipo estatico e Animal)
That's all for now.
Thanks for reading!
Top comments (0)