Funções de escopo em Kotlin

A biblioteca padrão do Kotlin contém diversas funções cuja única finalidade é executar um bloco de código dentro do contexto de um objeto. Quando você chama uma dessas funções em um objeto com uma expressão lambda fornecida, cria-se um escopo temporário. Nesse escopo, você pode acessar o objeto sem o seu nome. Essas funções são chamadas de funções de escopo.
Existem cinco delas:
- `let`
- `run`
- `with`
- `apply`
- `also`
Basicamente, todas essas funções executam a mesma ação: executar um bloco de código em um objeto. O que as diferencia é como esse objeto se torna disponível dentro do bloco e qual o resultado da expressão como um todo.
Um exemplo típico de como usar uma função de escopo:
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}Se você escrever o mesmo sem o “let”, terá que introduzir uma nova variável e repetir o nome dela sempre que a usar.
val alice = Person("Alice", 20, "Amsterdam")
println(alice)
alice.moveTo("London")
alice.incrementAge()
println(alice)Por que usar funções de escopo?
- Código legível: Elas tornam seu código mais expressivo e conciso.
- Escopos temporários: Permitem realizar operações em objetos dentro de um escopo restrito.
- Evitam verificações de nulo: Reduzem o código repetitivo para garantir a segurança contra nulos.
- Encadeamento de operações: Simplificam operações como inicializar objetos, configurar propriedades ou aplicar transformações.
Como as funções de escopo diferem?
Cada função de escopo possui:
- Um objeto de contexto: o objeto sobre o qual ela opera.
- Um valor de retorno: o próprio objeto ou o resultado do bloco.
- Uma referência ao objeto de contexto: pode ser acessada como `this` ou `it`.
As funções de escopo não introduzem novas capacidades técnicas, mas podem tornar seu código mais conciso e legível.
Devido às muitas semelhanças entre as funções de escopo, escolher a mais adequada para o seu caso de uso pode ser complicado. A escolha depende principalmente da sua intenção e da consistência de uso no seu projeto. Abaixo, fornecemos descrições detalhadas das diferenças entre as funções de escopo e suas convenções.
Para ajudar você a escolher a função de escopo mais adequada à sua necessidade, fornecemos esta tabela que resume as principais diferenças entre elas.
Seleção de função
| Função | Referência do objeto | Valor de retorno | É uma função de extensão |
|---|---|---|---|
| let | it | Resultado lambda | Sim |
| run | this | Resultado lambda | Sim |
| run | – | Resultado lambda | Não: chamado sem o objeto de contexto |
| with | this | Resultado lambda | Não: recebe o objeto de contexto como argumento. |
| apply | this | Objeto de contexto | Sim |
| also | it | Objeto de contexto | Sim |
let
A função let é usada para realizar operações em um objeto anulável e retornar um resultado. Ela é frequentemente usada para verificar valores nulos ou encadear transformações.
Exemplo: Verificando e Transformando um Objeto Anulável
val name: String? = "Kotlin"
val length = name?.let {
println("Name: $it")
it.length
}
println(length) // Output: 6Quando usar let:
- Para evitar exceções de ponteiro nulo.
- Quando você precisa transformar o objeto e retornar um resultado.
apply
A função apply é usada para configurar um objeto. Ela retorna o próprio objeto, sendo ideal para inicializar propriedades.
Exemplo: Imagine que você está criando um objeto de interface do usuário e precisa definir várias propriedades.
val button = Button(context).apply {
text = "Click Me"
isEnabled = true
setOnClickListener { println("Button clicked!") }
}
// Usage
println(button.text) // Outputs: Click MeQuando usar apply:
- Quando você precisa inicializar ou modificar um objeto.
run
A função run combina as funcionalidades de let e apply. Ela executa um bloco de código e retorna o resultado.
Exemplo: Realizar operações e retornar um resultado
val user = User("Anand", 25)
val isAdult = user.run {
println("Name: $name, Age: $age")
age >= 18
}
println(isAdult) // Output: trueQuando usar run:
- Quando você precisa realizar operações em um objeto e retornar um resultado.
also
A função also é usada quando você deseja executar ações adicionais sem modificar o objeto.
Exemplo: Ações de registro
val numbers = mutableListOf(1, 2, 3).also {
println("Original List: $it")
it.add(4)
it.remove(1)
}
println(numbers) // Output: [2, 3, 4]Quando usar also:
- Quando você deseja executar efeitos colaterais (por exemplo, registro ou depuração).
with
A função with é usada para operar diretamente em um objeto. Ela é frequentemente usada para agrupar operações em um objeto.
Exemplo: Imagine que você tenha um objeto de configuração que requer várias configurações.
fun configureSettings(): Settings {
val settings = Settings()
with(settings) {
enableDarkMode()
setLanguage("en")
setRegion("US")
}
return settings
}
// Usage
val settings = configureSettings()
println(settings.language) // Outputs: enQuando usar with:
- Quando você precisa realizar várias operações em um único objeto.
Qual a diferença entre it e this em funções de escopo?
- it: Usado quando o objeto é acessado por um nome implícito em funções de escopo como let e also.
- this: Usado quando o objeto é referenciado como um receptor em funções de escopo como apply, run e with.
0 comentários