Funções de Escopo do Kotlin
- 9 minsRecentemente comecei a trabalhar em um projeto em Kotlin, e no trabalho tenho a oportunidade de aprender e a compartilhar conhecimento com meu time. Esse foi o primeiro assunto que escolhi compartilhar com eles :)
Esse post é o compilado do que li e entendi ou não sobre o assunto.
O que são Funções de Escopo (Scope Functions)?
São funções da biblioteca padrão do Kotlin cujo o objetivo é executar um bloco de código dentro de um escopo/contexto de um objeto que podem ou não ter um valor de retorno. São cinco funções: let
, run
, with
, apply
e also
.
Para começar vamos utilizar a classe Product
como exemplo:
data class Product(
var title: String,
var price: Double,
var isActive:Boolean
){
fun deactivate(){
isActive = false
}
}
var product = Product("Smarthphone", 999.99, true)
Quando queremos mudar os atributo de product
fazemos isso:
product.title = "Smarthpone Bonitono"
product.price = 1_000.00
product.deativate()
Com as funções de escopo também é possível mudar os atributos e deixar o código mais com o estilo do Kotlin.
Let
Podemos utilizar o let
para alterar os atributos de product
e usamos o it
para referenciar o product
.
product.let {
it.title = "Smarthpone Bonitono"
it.price = 1_000.00
it.deactivate()
}
É possível trocar o it
para qualquer outra variável para referenciar o product:
product.let { att ->
att.title = "Smarthpone Bonitono"
att.price = 1_000.00
att.deactivate()
}
print(product)
// Product(title=Smarthpone Bonitono, price=1000.0, isActive=false)
Logo, os atributos de product
foram modificados com let
.
Agora vamos entender o valor de retorno do let
:
var result = product.let {
it.title = "Smarthpone Bonitono"
it.price = 1_000.00
it.deactivate()
}
print(result)
// kotlin.Unit
Ao imprimir a variável result
o retorno é um kotlin.Unit significa que o retorno é um valor não útil. Portanto, concluímos que o let
não retorna um valor.
Podemos utilizar o let
quando invocamos uma ou mais funções em resultados de chamadas encadeadas:
val numbers = mutableListOf("one", "two", "three", "four", "five")
numbers.map { it.length }.filter { it > 3 }.let {
println(it)
}
Se dentro do bloco de código do let
tiver apenas uma função com o argumento it
, podemos escrever o escopo da função let
como:
numbers.map { it.length }.filter { it > 3 }.let(::println)
Run
Também é possível utilizar o run
para mudar os atributos de product
e utilizamos o this
para referenciar o escopo do objeto:
var product = Product("Smarthphone", 999.99, true)
product.run {
this.title = "Smarthpone Bonitono"
this.price = 700.00
this.deactivate()
}
O uso do this
é opcional, e também deixa o código redundante, portanto podemos escrever dessa forma:
product.run {
title = "Smarthpone Bonitono"
price = 700.00
deactivate()
}
Vamos entender o retorno do run
:
var result = product.run {
title = "Smarthpone Bonitono"
price = 700.00
deactivate()
}
println(result)
//kotlin.Unit
Ao imprimir a variável result
o retorno é um [kotlin.Unit
,](https://kotlinlang.org/docs/functions.html#unit-returning-functions) significa que o retorno é um valor não útil. Portanto, concluímos que o run
não retorna um valor.
Podemos utilizar o run
para executar operações sobre um objeto e obter um resultado dentro de um escopo.
With
Utilizamos o with
para executar funções no objeto dentro de um contexto. Podemos ler como “com esse objeto, faça”
var product = Product("Smarthphone", 999.99, true)
with(product) {
deactivate()
println("produto desativado")
}
// produto desativado
O valor de retorno do with
é um kotlin.Unit
var result = with(product) {
deactivate()
println("produto desativado")
}
println(result)
// produto desativado
// kotlin.Unit
Apply
Podemos utilizar o apply
para alterar os atributos de product
, utilizamos o this
para referenciar o escopo do objeto. Podemos ler “aplique as seguintes atribuições ao objeto”
var product = Product("Smarthphone", 999.99, true)
product.apply {
this.title = "Smarthpone Bonitono"
this.price = 1_000.00
this.deactivate()
}
O uso do this
é opcional e também deixa o código redundante, portanto podemos escrever dessa forma:
product.apply {
title = "Smarthpone Bonitono"
price = 1_000.00
deactivate()
}
O valor de retorno do apply
é o próprio objeto, podemos imprimir a variável result
para entender isso:
var result = product.apply {
title = "Smarthpone Bonitono"
price = 1_000.00
deactivate()
}
println(result)
// Product(title=Smarthpone Bonitono, price=1000.0, isActive=true)
Also
Usamos o also
para ações que utilizam o objeto do contexto como argumento ou quando precisamos de uma referência ao invés das propriedades e funções. Podemos ler como: “e também faça com o objeto”.
Para referenciar o objeto dentro do escopo utilizamos o it
var product = Product("Smarthphone", 999.99, true)
product.apply {
title = "Smarthpone Bonitono"
price = 700.00
deactivate()
}.also{ println("Promoção do Produto $it") }
// Promoção do Produto Product(title=Smarthpone Bonitono, price=700.0, isActive=false)
Objeto nulos
Quando tivermos um objeto que possa ser nulo, as funções de escopo garantem que a função será chamada apenas se o objeto for não nulo:
var product2: Product? = null
// O ? permite que a variável seja nula
product2?.let {
it.title = "tv"
it.price = 100.00
it.isActive = false
}
println(product2)
// null
Resumo
Função | Retorno | Variável dentro do escopo | Uso |
---|---|---|---|
Let | Unit/Lambda* | it | Funções com chamadas encadeadas e checagem de objetos nulos |
Run | Unit/Lambda* | this | Inicialização do objeto e o cálculo do valor de retorno |
With | Unit/Lambda* | this | Executar funções no objeto dentro de um contexto. |
Apply | Objeto | this | Inicializar e configurar um objeto |
Also | Objeto | it | Ações adicionais que não alteram o objeto |
* Na própria documentação do Kotlin diz que retorna o resultado lambda
Link útil
Você pode testar o código usando o Kotlin Playground, divirta-se :)
Referências
-
Youtube Playlist - Kotlin Scope Functions Explained
-
Documentação Kotlin - Scope Functions
-
Documentação Kotlin - Unit
-
Artigo Medium - Kotlin Scoping Functions apply vs. with, let, also, and run
-
Artigo Medium - Kotlin: let, run, with, also ou apply?
-
Artigo Medium - Kotlin Scope Functions Made Simple
Espero que você tenha entendido sobre as funções de escopo do Kotlin!
Obrigada por ter lido <3