Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

743
Visualizações
Ejemplo de cuándo debemos usar run, let, apply, also y with en Kotlin

Deseo tener un buen ejemplo para cada función ejecutar, dejar, aplicar, también, con

He leído este artículo pero todavía falta un ejemplo.

over 4 years ago · Santiago Trujillo
6 Respostas
Responde à pergunta

0

Según mi experiencia, dado que tales funciones son azúcar sintáctica en línea sin diferencia de rendimiento, siempre debe elegir la que requiere escribir la menor cantidad de código en el lamda.

Para hacer esto, primero determine si desea que la lambda devuelva su resultado (elija run / let ) o el objeto mismo (elija apply / also ); luego, en la mayoría de los casos, cuando la lambda es una sola expresión, elija las que tengan el mismo tipo de función de bloque que esa expresión, porque cuando es una expresión de receptor, this puede omitir, cuando es una expresión de parámetro, it más corta que this :

 val a: Type = ... fun Type.receiverFunction(...): ReturnType { ... } a.run/*apply*/ { receiverFunction(...) } // shorter because "this" can be omitted a.let/*also*/ { it.receiverFunction(...) } // longer fun parameterFunction(parameter: Type, ...): ReturnType { ... } a.run/*apply*/ { parameterFunction(this, ...) } // longer a.let/*also*/ { parameterFunction(it, ...) } // shorter because "it" is shorter than "this"

Sin embargo, cuando la lambda consiste en una mezcla de ellos, depende de usted elegir el que se adapte mejor al contexto o con el que se sienta más cómodo.

Además, use los que tienen la función de bloque de parámetros cuando se necesita deconstrucción:

 val pair: Pair<TypeA, TypeB> = ... pair.run/*apply*/ { val (first, second) = this ... } // longer pair.let/*also*/ { (first, second) -> ... } // shorter

Aquí hay una breve comparación entre todas estas funciones del curso oficial de Kotlin de JetBrains en Coursera Kotlin para desarrolladores de Java : tabla de diferencias Implementaciones simplificadas

over 4 years ago · Santiago Trujillo Relatório

0

let, also, apply, takeIf, takeUnless son funciones de extensión en Kotlin.

Para comprender estas funciones, debe comprender las funciones de extensión y las funciones de Lambda en Kotlin.

Función de extensión:

Mediante el uso de la función de extensión, podemos crear una función para una clase sin heredar una clase.

Kotlin, similar a C# y Gosu, ofrece la posibilidad de ampliar una clase con nuevas funciones sin tener que heredar de la clase ni utilizar ningún tipo de patrón de diseño como Decorator. Esto se hace a través de declaraciones especiales llamadas extensiones. Kotlin admite funciones de extensión y propiedades de extensión.

Entonces, para encontrar solo números en String , puede crear un método como el siguiente sin heredar la clase String .

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

puede usar la función de extensión anterior de esta manera,

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

que se imprime true .

Funciones lambdas:

Las funciones Lambda son como la interfaz en Java. Pero en Kotlin, las funciones lambda se pueden pasar como un parámetro en funciones.

Ejemplo:

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

Puede ver, el bloque es una función lambda y se pasa como un parámetro. Puede usar la función anterior de esta manera,

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

La función anterior se imprimirá así,

 Block executed true

Espero que ahora tenga una idea sobre las funciones de extensión y las funciones de Lambda. Ahora podemos ir a las funciones de extensión una por una.

dejar

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

Dos tipos T y R utilizados en la función anterior.

 T.let

T podría ser cualquier objeto como la clase String. para que pueda invocar esta función con cualquier objeto.

 block: (T) -> R

En el parámetro de let, puede ver la función lambda anterior. Además, el objeto que invoca se pasa como un parámetro de la función. Entonces puede usar el objeto de clase de invocación dentro de la función. luego devuelve la R (otro objeto).

Ejemplo:

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

En el ejemplo anterior, toma String como un parámetro de su función lambda y devuelve Pair a cambio.

De la misma manera, funciona otra función de extensión.

además

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

La función de extensión also toma la clase que invoca como un parámetro de función lambda y no devuelve nada.

Ejemplo:

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

aplicar

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

Igual que también pero el mismo objeto de invocación pasado como la función para que pueda usar las funciones y otras propiedades sin llamarlo o el nombre del parámetro.

Ejemplo:

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

Puede ver en el ejemplo anterior las funciones de la clase String invocadas directamente dentro de la función lambda.

tomar si

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

Ejemplo:

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

En el ejemplo anterior, number tendrá una cadena de número de phoneNumber solo si coincide con la regex . De lo contrario, será null .

tomar a menos que

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

Es lo contrario de takeIf.

Ejemplo:

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

number tendrá una cadena de phoneNumber solo si no coincide con la regex . De lo contrario, será null .

Puede ver respuestas similares, lo que es útil aquí , también diferencia entre kotlin, aplicar, dejar, usar, tomar si y tomar a menos que en Kotlin

over 4 years ago · Santiago Trujillo Relatório

0

Todas estas funciones se utilizan para cambiar el alcance de la función actual/la variable. Se utilizan para mantener cosas que pertenecen juntas en un solo lugar (principalmente inicializaciones).

Aquí hay unos ejemplos:

run : devuelve todo lo que desea y vuelve a definir el alcance de la variable en la que this usa

 val password: Password = PasswordGenerator().run { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000 generate() }

El generador de contraseñas ahora tiene this nuevo alcance y, por lo tanto, podemos configurar seed , hash y hashRepetitions sin usar una variable. generate() devolverá una instancia de Password .

apply es similar, pero devolverá this :

 val generator = PasswordGenerator().apply { seed = "someString" hash = {s -> someHash(s)} hashRepetitions = 1000 } val pasword = generator.generate()

Eso es particularmente útil como reemplazo del patrón Builder y si desea reutilizar ciertas configuraciones.

let : se usa principalmente para evitar verificaciones nulas, pero también se puede usar como reemplazo de run . La diferencia es que this seguirá siendo el mismo que antes y usted accede a la variable re-alcance it :

 val fruitBasket = ... apple?.let { println("adding a ${it.color} apple!") fruitBasket.add(it) }

El código anterior agregará la manzana a la cesta solo si no es nulo. También tenga en cuenta que ya it es opcional , por lo que no se encontrará con una NullPointerException aquí (es decir, no necesita usar ?. para acceder a sus atributos)

also : úselo cuando quiera usar apply , pero no quiera ensombrecer this

 class FruitBasket { private var weight = 0 fun addFrom(appleTree: AppleTree) { val apple = appleTree.pick().also { apple -> this.weight += apple.weight add(apple) } ... } ... fun add(fruit: Fruit) = ... }

El uso de apply here sombrearía this , de modo que this.weight se referiría a la manzana y no a la canasta de frutas.


Nota: Tomé descaradamente los ejemplos de mi blog .

over 4 years ago · Santiago Trujillo Relatório

0

Hay algunos artículos más como aquí y aquí que vale la pena echar un vistazo.

Creo que se debe a cuándo necesita una versión más breve y concisa en unas pocas líneas, y para evitar la bifurcación o la verificación de declaraciones condicionales (como si no es nulo, entonces haga esto).

Me encanta este gráfico simple, así que lo vinculé aquí. Lo pueden ver a partir de esto escrito por Sebastiano Gottardo.

ingrese la descripción de la imagen aquí

Por favor, mire también el cuadro que acompaña a mi explicación a continuación.

Concepto

Creo que es una forma de juego de roles dentro de su bloque de código cuando llama a esas funciones + si quiere volver (para encadenar funciones de llamada, o establecer la variable de resultado, etc.).

Arriba está lo que pienso.

Ejemplo de concepto

Veamos ejemplos de todos ellos aquí.

1.) myComputer.apply { } significa que desea actuar como actor principal (quiere pensar que es una computadora) y quiere recuperarse (computadora) para que pueda hacer

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

Sí, usted mismo simplemente instala las aplicaciones, se bloquea y se guarda como referencia para permitir que otros vean y hagan algo con ellas.

2.) myComputer.also {} significa que está completamente seguro de que no es una computadora, es un extraño que quiere hacer algo con él y también quiere que sea una computadora como resultado devuelto.

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

3.) with(myComputer) { } significa que eres el actor principal (computadora), y no te quieres recuperar como resultado.

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

4.) myComputer.run { } significa que eres el actor principal (computadora), y no te quieres recuperar como resultado.

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

pero es diferente de with { } en un sentido muy sutil en el que puede encadenar una llamada run { } como la siguiente

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

Esto se debe a que run {} es una función de extensión, pero with { } no lo es. Así que llama a run { } y this dentro del bloque de código se reflejará en el tipo de objeto de la persona que llama. Puede ver esto como una excelente explicación de la diferencia entre run {} y with {} .

5.) myComputer.let { } significa que usted es un extraño que mira la computadora y quiere hacer algo al respecto sin preocuparse de que la instancia de la computadora le sea devuelta nuevamente.

 myComputer.let { myGrandpa.installVirusOn(it) }

La manera de mirarlo

also tiendo a mirar y let como algo que es externo, afuera. Cada vez que dices estas dos palabras, es como si trataras de actuar mal. let instale el virus en esta computadora y also cuélguelo. Así que esto determina la parte de si eres actor o no.

Para la parte del resultado, está claramente ahí. also expresa que también es otra cosa, por lo que aún conserva la disponibilidad del objeto en sí. Así lo devuelve como resultado.

Todo lo demás se asocia con this . Además, run/with claramente no está interesado en devolver el objeto a sí mismo. Ahora puedes diferenciarlos todos.

Creo que a veces, cuando nos alejamos del 100 % de la programación/los ejemplos basados en la lógica, entonces estamos en una mejor posición para conceptualizar las cosas. Pero eso depende verdad :)

over 4 years ago · Santiago Trujillo Relatório

0

Hay 6 funciones de alcance diferentes:

  1. T.ejecutar
  2. T.let
  3. T.aplicar
  4. T.también
  5. con
  6. correr

Preparé una nota visual como la siguiente para mostrar las diferencias:

 data class Citizen(var name: String, var age: Int, var residence: String)

ingrese la descripción de la imagen aquí

La decisión depende de tus necesidades. Los casos de uso de diferentes funciones se superponen, de modo que puede elegir las funciones en función de las convenciones específicas utilizadas en su proyecto o equipo.

Aunque las funciones de alcance son una forma de hacer que el código sea más conciso, evite usarlas en exceso: puede disminuir la legibilidad de su código y generar errores. Evite anidar funciones de alcance y tenga cuidado al encadenarlas: es fácil confundirse sobre el objeto de contexto actual y el valor de this o it.

Aquí hay otro diagrama para decidir cuál usar de https://medium.com/@elye.project/mastering-kotlin-standard-functions-run-with-let-also-and-apply-9cd334b0ef84 ingrese la descripción de la imagen aquí

Algunas convenciones son las siguientes:

Úselo también para acciones adicionales que no alteran el objeto, como el registro o la impresión de información de depuración.

 val numbers = mutableListOf("one", "two", "three") numbers .also { println("The list elements before adding new one: $it") } .add("four")

El caso común de apply es la configuración del objeto.

 val adam = Person("Adam").apply { age = 32 city = "London" } println(adam)

Si necesita sombra, use ejecutar

 fun test() { var mood = "I am sad" run { val mood = "I am happy" println(mood) // I am happy } println(mood) // I am sad }

Si necesita devolver el objeto receptor en sí, use aplicar o también

over 4 years ago · Santiago Trujillo Relatório

0

Debo admitir que la diferencia no es tan obvia a primera vista, entre otras cosas porque estas 5 funciones suelen ser intercambiables. Aquí está mi entendimiento:

APLICAR -> Inicializar un objeto con estas propiedades y esperar el objeto

 val paint = Paint().apply { this.style = Paint.Style.FILL this.color = Color.WHITE }

LET -> Aislar un fragmento de código y esperar el resultado

 val result = let { val b = 3 val c = 2 b + c }

o

 val a = 1 val result = a.let { val b = 3 val c = 2 it + b + c }

o

 val paint: Paint? = Paint() paint?.let { // here, paint is always NOT NULL // paint is "Paint", not "Paint?" }

TAMBIÉN -> Ejecutar 2 operaciones al mismo tiempo y esperar el resultado

 val a = 1 val b = 3 a = b.also { b = a }

CON -> Haga algo con esta variable/objeto y no espere un resultado (el encadenamiento NO está permitido)

 with(canvas) { this.draw(x) this.draw(y) }

EJECUTAR -> Hacer algo con esta variable/objeto y no esperar un resultado (se permite el encadenamiento)

 canvas.run { this.draw(x) this.draw(y) }

o

 canvas.run {this.draw(x)}.run {this.draw(x)}
over 4 years ago · Santiago Trujillo Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda