Kotlin: run, let, apply, also, with — quando usar o quê? Análise completa com exemplos
Olá, amigo! Se você está estudando Kotlin e quer escrever código limpo e conciso, mais cedo ou mais tarde encontrará cinco funções mágicas: run, let, apply, also e with. Estas são funções de escopo (scope functions) — elas permitem executar código no contexto de um objeto e simplificam bastante a vida.
Mas eis o problema: muitos iniciantes (e não só) ficam confusos sobre quando usar cada uma. Esta é uma das perguntas mais populares no Stack Overflow, e hoje vamos entender de uma vez por todas como não errar. Não vamos apenas listar regras — vamos mostrar exemplos reais da prática que você pode usar imediatamente em seus projetos.
O que são funções de escopo e para que servem?
Funções de escopo são funções que criam um escopo temporário para um objeto. Dentro desse escopo, você pode acessar o objeto através de it ou this. A principal diferença entre elas é como retornam o resultado e como referenciam o contexto.
Aqui está uma breve folha de dicas que vamos preencher com exemplos:
let— contexto:it, retorna: resultado da lambda. Usado para verificações de nulidade e encadeamento de chamadas.run— contexto:this, retorna: resultado da lambda. Função versátil, frequentemente para inicialização e cálculos.apply— contexto:this, retorna: o próprio objeto. Ideal para configurar propriedades de um objeto.also— contexto:it, retorna: o próprio objeto. Bom para ações adicionais (logging, verificações).with— não é uma função de extensão, contexto:this, retorna: resultado da lambda. Conveniente para agrupar chamadas de um objeto sem criar um novo.
Lembre-se da regra principal: a escolha da função depende do que você precisa — retornar o objeto ou o resultado, e como você quer referenciar o contexto (através de it ou this).
1. let — o rei das cadeias seguras
let é seu melhor amigo quando precisa trabalhar com objetos anuláveis. Ele executa o código apenas se o objeto não for nulo. O contexto é passado como it.
Exemplo: transformação segura
val name: String? = "André"// Sem let:if (name != null) { println("Comprimento do nome: ${name.length}")}
// Com let (muito mais elegante):name?.let { println("Comprimento do nome: ${it.length}")}let também é ótimo para encadeamento de operações. Por exemplo, quando precisa transformar um objeto em outro:
val numbers = listOf(1, 2, null, 4, null, 6)val nonNullSquared = numbers .mapNotNull { it } .let { list -> list.map { it * it } }println(nonNullSquared) // [1, 4, 16, 36]Quando usar let:
- Verificação de nulo (caso mais comum).
- Transformação de um valor em outro.
- Execução de uma cadeia de operações com o resultado.
2. apply — construtor sem palavras desnecessárias
apply retorna o próprio objeto, e dentro da lambda o contexto é this. Esta é a ferramenta ideal para configurar um objeto antes de usá-lo. Esqueça longos blocos de set!
Exemplo: configuração de View (Android) ou data class
data class User(var name: String = "", var age: Int = 0)
val user = User().apply { name = "Maria" age = 25}println(user) // User(name=Maria, age=25)
// Ainda melhor — configuração de TextView:val textView = TextView(context).apply { text = "Olá, Kotlin!" textSize = 18f setTextCo