variavel - print kotlin




Exemplo de quando devemos usar executar, deixar, aplicar, também e com em Kotlin (3)

Eu gostaria de ter um bom exemplo para cada função executada, deixar, aplicar, também, com

Eu li este artigo, mas ainda falta um exemplo


De acordo com a minha experiência, uma vez que tais funções são açúcar sintático em linha sem diferença de desempenho, você deve sempre escolher aquele que requer escrever a menor quantidade de código no lamda.
Para fazer isso, primeiro determine se você deseja que o lambda retorne seu resultado (escolha run / let ) ou o próprio objeto (escolha apply / also ); então, na maioria dos casos, quando lambda é uma expressão única, escolha aquelas com o mesmo tipo de função de bloco que a expressão, porque quando é uma expressão de receptor, this pode ser omitido, quando é uma expressão de parâmetro, é menor que this :

val object: Type = ...

fun Type.receiverFunction(...): ReturnType { ... }
object.run/*apply*/ { receiverFunction(...) } // shorter because "this" can be omitted
object.let/*also*/ { it.receiverFunction(...) } // longer

fun parameterFunction(parameter: Type, ...): ReturnType { ... }
pair.run/*apply*/ { parameterFunction(this, ...) } // longer
pair.let/*also*/ { parameterFunction(it, ...) } // shorter because "it" is shorter than "this"

No entanto, quando o lambda consiste em uma mistura deles, cabe a você escolher o que se encaixa melhor no contexto ou com o qual você se sente mais confortável.
Além disso, use aqueles com função de bloco de parâmetro quando a desconstrução é necessária:

val pair: Pair<TypeA, TypeB> = ...

object.run/*apply*/ {
    val (first, second) = this
    ...
} // longer
object.let/*also*/ { (first, second) -> ... } // shorter

Aqui está uma breve comparação entre todas essas funções do curso oficial Kotlin da JetBrains no Coursera Kotlin para desenvolvedores Java :


Há mais alguns artigos como here , e here vale a pena dar uma olhada.

Eu acho que é até quando você precisa de um mais curto, mais conciso dentro de algumas linhas, e para evitar a verificação de instruções de ramificação ou condicional (como se não for nulo, então faça isso).

Eu amo esse gráfico simples, então eu o vinculei aqui. Você pode ver here como foi escrito por Sebastiano Gottardo.

Por favor, veja também o gráfico que acompanha minha explicação abaixo.

Conceito

Eu acho que isso funciona como um papel dentro do seu bloco de código quando você chama essas funções + se você quer você mesmo de volta (para encadear funções de chamada, ou definir para variável de resultado, etc).

Acima é o que eu penso.

Exemplo de conceito

Vamos ver exemplos para todos eles aqui

1.) myComputer.apply { } significa que você quer atuar como um ator principal (você quer pensar que você é um computador), e você quer você mesmo de volta (computador) para que você possa fazer

var crashedComputer = myComputer.apply { 
    // you're the computer, you yourself install the apps
    // note: installFancyApps is one of methods of computer
    installFancyApps() 
}.crash()

Sim, você mesmo apenas instala os aplicativos, falha e salva a si mesmo como referência para permitir que outras pessoas vejam e façam algo com ele.

2.) myComputer.also {} significa que você tem certeza absoluta de que não é um computador, é um estranho que quer fazer algo com ele e também quer um computador como resultado retornado.

var crashedComputer = myComputer.also { 
    // now your grandpa does something with it
    myGrandpa.installVirusOn(it) 
}.crash()

3.) with(myComputer) { } significa que você é ator principal (computador), e você não se quer como resultado.

with(myComputer) {
    // you're the computer, you yourself install the apps
    installFancyApps()
}

4.) myComputer.run { } significa que você é o ator principal (computador), e você não se quer como resultado.

myComputer.run {
    // you're the computer, you yourself install the apps
    installFancyApps()
}

mas é diferente de with { } em um sentido muito sutil de que você pode encadear chamadas run { } como as seguintes

myComputer.run {
    installFancyApps()
}.run {
    // computer object isn't passed through here. So you cannot call installFancyApps() here again.
    println("woop!")
}

Isto é devido a run {} é função de extensão, mas with { } não é. Então você chama a run { } e this dentro do bloco de código será refletido para o tipo de objeto chamador. Você pode ver this como uma excelente explicação para a diferença entre run {} e with {} .

5.) myComputer.let { } significa que você é de fora que olha para o computador e quer fazer algo sobre isso sem qualquer cuidado para que a instância do computador seja devolvida novamente a você.

myComputer.let {
    myGrandpa.installVirusOn(it)
}

A maneira de olhar para ele

Eu costumo olhar also e let como algo externo, externo. Sempre que você diz essas duas palavras, é como se você tentasse agir de acordo com alguma coisa. let instalar vírus neste computador e also travá-lo. Então, isso se aplica à questão de se você é ator ou não.

Para a parte do resultado, está claramente lá. also expressa que também é outra coisa, então você ainda mantém a disponibilidade do próprio objeto. Assim, ele retorna como resultado.

Tudo o resto associa-se a this . Além disso, run/with claramente não interessa a devolução do objeto em si. Agora você pode diferenciar todos eles.

Eu acho que, às vezes, quando nos afastamos de 100% de exemplos baseados em programação / lógica, então estamos em melhor posição para conceituar as coisas. Mas isso depende certo :)


vamos, também, aplicar, takeIf, takeUnless são funções de extensão no Kotlin.

Para entender essas funções, você precisa entender as funções de extensão e as funções do Lambda no Kotlin.

Função de extensão:

Pelo uso da função de extensão, podemos criar uma função para uma classe sem herdar uma classe.

O Kotlin, semelhante ao C # e ao Gosu, oferece a capacidade de estender uma classe com nova funcionalidade sem precisar herdar da classe ou usar qualquer tipo de padrão de design, como o Decorator. Isso é feito por meio de declarações especiais chamadas extensões. Kotlin suporta funções de extensão e propriedades de extensão.

Assim, para encontrar apenas números na String , você pode criar um método como o abaixo, sem herdar a classe String .

fun String.isNumber(): Boolean = this.matches("[0-9]+".toRegex())

você pode usar a função de extensão acima como esta,

val phoneNumber = "8899665544"
println(phoneNumber.isNumber)

qual é imprime true .

Funções Lambda:

As funções do Lambda são como Interface em Java. Mas no Kotlin, funções lambda podem ser passadas como um parâmetro em funções.

Exemplo:

fun String.isNumber(block: () -> Unit): Boolean {
    return if (this.matches("[0-9]+".toRegex())) {
        block()
        true
    } else false
}

Você pode ver que o bloco é uma função lambda e é passado como um parâmetro. Você pode usar a função acima assim,

val phoneNumber = "8899665544"
    println(phoneNumber.isNumber {
        println("Block executed")
    })

A função acima será impressa assim,

Block executed
true

Espero que agora você tenha uma ideia sobre as funções de extensão e as funções do Lambda. Agora podemos ir para as funções de extensão, uma por uma.

deixei

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

Dois tipos T e R usados ​​na função acima.

T.let

T poderia ser qualquer objeto como a classe String. então você pode invocar essa função com qualquer objeto.

block: (T) -> R

No parâmetro let, você pode ver a função lambda acima. Além disso, o objeto de chamada é passado como um parâmetro da função. Portanto, você pode usar o objeto de classe de chamada dentro da função. então retorna o R (outro objeto).

Exemplo:

val phoneNumber = "8899665544"
val numberAndCount: Pair<Int, Int> = phoneNumber.let { it.toInt() to it.count() }

No exemplo acima, vamos pegar String como um parâmetro de sua função lambda e ela retorna Pair de volta.

Da mesma forma, outras funções de extensão funcionam.

Além disso

public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }

A função de extensão also usa a classe de chamada como um parâmetro da função lambda e não retorna nada.

Exemplo:

val phoneNumber = "8899665544"
phoneNumber.also { number ->
    println(number.contains("8"))
    println(number.length)
 }

Aplique

public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }

Igual a também, mas o mesmo objeto de chamada passado como a função, para que você possa usar as funções e outras propriedades sem chamá-lo ou o nome do parâmetro.

Exemplo:

val phoneNumber = "8899665544"
phoneNumber.apply { 
    println(contains("8"))
    println(length)
 }

Você pode ver no exemplo acima as funções da classe String chamadas diretamente dentro da função lambda.

takeIf

public inline fun <T> T.takeIf(predicate: (T) -> Boolean): T? = if (predicate(this)) this else null

Exemplo:

val phoneNumber = "8899665544"
val number = phoneNumber.takeIf { it.matches("[0-9]+".toRegex()) }

No exemplo acima, o number terá uma string de phoneNumber somente se ele corresponder ao regex . Caso contrário, será null .

takeUnless

public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null

É o reverso do takeIf.

Exemplo:

val phoneNumber = "8899665544"
val number = phoneNumber.takeUnless { it.matches("[0-9]+".toRegex()) }

number terá uma string de phoneNumber somente se não corresponder à regex . Caso contrário, será null .

Você pode ver respostas semelhantes que é útil aqui diferença entre kotlin também, aplicar, let, use, takeIf e takeUnless em Kotlin





kotlin