Programação Avançada Kotlin Parte 3

Tempo de leitura: 4 minutes

Neste artigo, vamos verificar os Escopos de Funções em Kotlin e como usá-las.

 

O que são Escopo de Funções?

Em Kotlin, as funções são de grande importância. Funções de escopo são funções que executam um bloco de código dentro do contexto de um objeto. Quando chamamos essas funções em um objeto com uma expressão lambda, isso forma um escopo temporário onde podemos realizar nossas operações. Nesse escopo, o contexto do objeto é geralmente referido como ele (ou qualquer nome personalizado) ou baseado na função de escopo que estamos usando.

Vamos dar um exemplo simples da função run:

fun sample() {
    var a = 1   
    run {
        val a = 2
        println(a) // prints value 2
    }
    println(a)  // prints value 1
}

Aqui, dentro de sample (), um valor é definido como 1, mas dentro do escopo de execução ele foi redefinido – o valor modificado é válido até o final do escopo. As funções de escopo são muito úteis e podemos encontrar muitas maneiras de usá-las.

 

Diferentes Espoco de Funções

Existem cinco funções de escopo diferentes disponíveis no Kotlin. São eles: let, run, with, apply e também. Todas as cinco funções fazem a mesma coisa: executam um bloco de código em um objeto. Eles diferem de duas maneiras principais:

  • A maneira de se referir ao objeto de contexto
  • O valor de retorno.

Antes de começarmos, vamos explorar o objeto de contexto. Geralmente nos referimos ao objeto de contexto dentro de uma expressão lambda usando um nome curto. Cada função de escopo usa uma das duas maneiras de acessar o objeto de contexto como um receptor lambda (this) ou como um argumento lambda (it). Vamos verificar cada um deles.

 

this – como o receptor

No escopo, as funções “apply”,  “run” e “with”, com o objeto de contexto, é referido pela palavra-chave “this”. Eles têm o objeto de contexto como um receptor lambda. Nesse caso, podemos omitir isso ao acessar os membros do objeto de contexto, tornando o código mais curto e limpo.

Se quisermos criar um objeto Person, fazemos assim:

val person = Person("Pavan")
     person.nickName = "Satya"
     person.age = 20
     println(person)

 

Usando “this” com escopo “apply”:

val person = Person("Pavan").apply {
              nickName = "Satya"
              age = 20
 }
 or
 val person = Person("Pavan").apply {
              this.itemName = "Satya"
              this.age = 20
 }

Todos os métodos acima são iguais – eles criam o mesmo objeto Person com os mesmos valores.

 

“Se ‘this’ omitido, pode ser difícil distinguir entre os membros receptores e os objetos ou funções externas. Portanto, ter o objeto de contexto como receptor (this) é recomendado para lambdas que operam principalmente nos membros do objeto: chame suas funções ou atribua propriedades ”

Documentação Kotlin

 

it – como o argumento

Nas funções de escopo “let” e “also”, o objeto de contexto é referido pela palavra-chave “it”. Eles têm o objeto de contexto como um argumento lambda. No entanto, temos uma opção para especificar o nome do argumento aqui, se não for especificado, o objeto é acessado pelo nome padrão implícito “it”. Quando não temos o objeto disponível implicitamente, como “this”, precisamos especificar “it” pré-anexado a eles ao chamar as funções ou propriedades do objeto.

val person = Person("Pavan").let {it->
                 it.nickName = "Satya"
                 it.age = 20
}
 or
val person = Person("Pavan").let {param->
                 param.itemName = "Satya"
                 param.age = 20
}

O Valor de Retorno

As funções de escopo diferem pelo resultado que retornam:

“apply” e “also” retornam o objeto de contexto.
“let”, “run” e “with” retornam o resultado lambda.

A função de escopo usada pode ser decidida com base no que fazemos em seguida à função de escopo.

A seguir, vamos dar uma olhada em cada uma das funções de escopo

 

let

inline fun <T, R> T.let(block: (T) -> R): R

Uma das funções de escopo mais amplamente utilizadas durante o desenvolvimento, principalmente para verificações de nulos. O objeto de contexto está disponível como um argumento (it). O valor de retorno é o resultado lambda. NullPointerException é comum na maioria das linguagens de programação. “Let” é usado principalmente para executar bloco de código apenas com valores não nulos. Para executar ações em um objeto não nulo, use o operador de chamada segura?. nele e chame let com as ações em seu lambda.

val greetMsg: String? = "Hello"   
//doSomesNonNullStuff(str)       // erro pode ocorrer porque greetMsg pode ser nulo
val length = greetMsg?.let { 
    println("greet message is  $it")        
    doSomesNonNullStuff(it)      // OK: 'it' não é nulo dentro de '? .Let {}'
    it.length
}

or 
val length = greetMsg?.let { str->
    println("greet message is  $str")        
    doSomesNonNullStuff(str)      // OK: 'str' não é nulo dentro de '? .Let {}'
    str.length
}

É basicamente usado para verificações nulas com ele como argumento e para transformação pega um tipo de entrada e retorna outro tipo como resultado.

 

run

inline fun <T, R> T.run(block: T.() -> R): R

O objeto de contexto está disponível como um receptor (this). O valor de retorno é o resultado lambda. run pode servir basicamente aos mesmos casos de uso, porém a única diferença é que o objeto de contexto está disponível como este.

var a = 1
println(a) // 1
a = run {
   val a = 2
   a
 }
println(a) //2

É útil quando nosso lambda contém a inicialização do objeto e o cálculo do valor de retorno.

 

apply

inline fun <T> T.apply(block: T.() -> Unit): T

O objeto de contexto está disponível como um receptor (this). O valor de retorno é o próprio objeto “.apply” não retorna um valor e opera principalmente nos membros do objeto receptor.

Val country = Country("USA")
country?.apply {
        name = "India"
}
printnl(country)

Aqui, a aplicação acessa as propriedades do nome da cidade e substitui seu valor. É semelhante a let – a única diferença é que apply não aceita uma instrução de retorno e sempre retorna o mesmo objeto receptor ao qual está se referindo.

 

also

inline fun  T.also(block: (T) -> Unit): T

O objeto de contexto está disponível como um argumento (it). O valor de retorno é o próprio objeto. É muito semelhante ao aplicar – a única diferença aqui é a maneira de se referir ao objeto de contexto. Em apply, podemos fornecer um nome personalizado, aumentando a legibilidade em casos de let.

val person = Person().also { it.name = "Andro" }

Pode ser usado para inicialização de objetos, melhorando a legibilidade do código.

 

with

inline fun <T, R> with(receiver: T, block: T.() -> R): R

O objeto de contexto é passado como um argumento, mas dentro do lambda, está disponível como um receptor (this). O valor de retorno é o resultado lambda. É semelhante a let and run em termos da transformação do objeto receptor em tipo de retorno.

data class Student(var firstName: String, var lastName: String)
var student = Student("Satya", "Pavan")

with(student)
    {
        firstName = "Androide"
        lastName = "Dev"
    }

É usado para melhor legibilidade e é recomendado para chamar funções no objeto de contexto sem fornecer o resultado lambda.

 

Resumo

Agora você deve ter uma ideia básica sobre o uso de funções de escopo no Kotlin