programar - Ejemplo de cuándo debemos usar ejecutar, dejar, aplicar, también y con Kotlin
programacion android kotlin (4)
Hay algunos artículos más como here , y here que vale la pena echar un vistazo.
Creo que es necesario cuando se necesita una respuesta más breve y concisa dentro de unas pocas líneas, y para evitar la bifurcación o la comprobación de sentencias condicionales (por ejemplo, si no es nula, haga esto).
Me encanta este gráfico simple, así que lo vinculé aquí. Puedes verlo a partir de here según lo escrito por Sebastiano Gottardo.
Por favor, mire también la tabla que acompaña mi explicación a continuación.
Concepto
Creo que es un juego de roles dentro de su bloque de código cuando llama a esas funciones + si desea regresar (para encadenar funciones de llamada o establecer como variable de resultado, etc.).
Arriba está lo que pienso.
Ejemplo de concepto
Veamos ejemplos para todos ellos aquí.
1.)
myComputer.apply { }
significa que quieres actuar como actor principal (quieres pensar que eres una computadora), y quieres que vuelvas (computadora) para poder hacerlo
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 solo instaló las aplicaciones, se bloqueó y se guardó como referencia para permitir que otros lo vean y hagan algo con él.
2.)
myComputer.also {}
significa que estás completamente seguro de que
no eres una
computadora, eres un extraño que quiere hacer algo con ella y también quiere que sea la 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 que
no te
quieres a ti mismo 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 que
no te
quieres a ti mismo como resultado.
myComputer.run {
// you''re the computer, you yourself install the apps
installFancyApps()
}
pero es diferente de
with { }
en un sentido muy sutil que puede encadenar la
run { }
llamadas
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 función de extensión, pero
with { }
no lo es.
Entonces llama a
run { }
y
this
dentro del bloque de código se reflejará en el tipo de objeto que llama.
Puede ver
this
para obtener una excelente explicación de la diferencia entre la
run {}
y
with {}
.
5.)
myComputer.let { }
significa que eres un extraño que mira la computadora y quieres hacer algo al respecto sin preocuparte de que la instancia de la computadora te sea devuelta nuevamente.
myComputer.let {
myGrandpa.installVirusOn(it)
}
La forma de verlo
Tiendo a mirar
also
y
let
que
let
algo externo, externo.
Cada vez que dices estas dos palabras, es como si trataras de actuar en algo.
let
instalar el virus en esta computadora, y
also
colóquelo.
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í.
Por lo tanto, lo devuelve como resultado.
Todo lo demás se asocia con
this
.
Además,
run/with
claramente no le interesa devolver el objeto a sí mismo.
Ahora puedes diferenciarlos a todos.
Creo que a veces, cuando nos alejamos de la programación 100% / basada en la lógica de los ejemplos, entonces estamos en una mejor posición para conceptualizar las cosas. Pero eso depende bien :)
Deseo tener un buen ejemplo para cada función ejecutada, let, apply, también, con
He leído este artículo pero aún no tengo un ejemplo
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 requiera 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 en sí (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 se trata de una expresión receptora, se puede omitir, cuando es una expresión de parámetro, es más corta 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"
Sin embargo, cuando el lambda consiste en una mezcla de ellos, depende de usted elegir el que mejor se adapte al contexto o con el que se sienta más cómodo.
Además, use los que tienen función de bloque de parámetros cuando se necesita deconstrucción:
val pair: Pair<TypeA, TypeB> = ...
object.run/*apply*/ {
val (first, second) = this
...
} // longer
object.let/*also*/ { (first, second) -> ... } // shorter
Aquí hay una breve comparación entre todas estas funciones del curso oficial Kotlin de JetBrains sobre Coursera Kotlin para desarrolladores de Java :
Todas estas funciones se utilizan para cambiar el alcance de la función actual / la variable. Se usan para mantener las cosas que pertenecen juntas en un solo lugar (principalmente inicializaciones).
Aquí hay unos ejemplos:
run
: devuelve todo lo que desee y vuelve a abarcar la variable en la que se utiliza
val password: Password = PasswordGenerator().run {
seed = "someString"
hash = {s -> someHash(s)}
hashRepetitions = 1000
generate()
}
El generador de contraseñas ahora se rescoca como
this
y, por lo tanto, podemos establecer
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 un reemplazo para el patrón Builder, y si desea reutilizar ciertas configuraciones.
let
: se usa principalmente para evitar comprobaciones nulas, pero también se puede usar como un reemplazo para la
run
.
La diferencia es que
this
seguirá siendo el mismo que antes y que accedes a la variable de nuevo alcance usándola:
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 nula.
También tenga en cuenta que ahora ya
no 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 ocultar
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
aquí sombrearía
this
, de modo que
this.weight
se referiría a la manzana y
no
a la cesta de frutas.
Nota: descaradamente tomé los ejemplos de mi blog
let, también, 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, proporciona la capacidad de extender una clase con una nueva funcionalidad sin tener que heredar de la clase o usar ningún tipo de patrón de diseño como Decorator. Esto se realiza a través de declaraciones especiales llamadas extensiones. Kotlin admite funciones de extensión y propiedades de extensión.
Entonces, para encontrar si solo hay números en la
String
, puede crear un método como el siguiente sin heredar
String
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)
lo cual se imprime
true
.
Funciones Lambda:
Las funciones de Lambda son como la interfaz en Java. Pero en Kotlin, las funciones lambda se pueden pasar como un parámetro en las funciones.
Ejemplo:
fun String.isNumber(block: () -> Unit): Boolean {
return if (this.matches("[0-9]+".toRegex())) {
block()
true
} else false
}
Como 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 tengas 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 de invocación 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.
entonces 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, let toma String como parámetro de su función lambda y devuelve Pair a cambio.
Del mismo modo, 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 de invocación 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 ni al 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 directamente invocadas 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, el
number
tendrá una cadena de
phoneNumber
de
phoneNumber
solo que coincide con la
regex
.
De lo contrario, será
null
.
tomar a menos
public inline fun <T> T.takeUnless(predicate: (T) -> Boolean): T? = if (!predicate(this)) this else null
Es el reverso de takeIf.
Ejemplo:
val phoneNumber = "8899665544"
val number = phoneNumber.takeUnless { it.matches("[0-9]+".toRegex()) }
number
tendrá una cadena de
phoneNumber
de
phoneNumber
solo si no coincide con la
regex
.
De lo contrario, será
null
.
Puede ver respuestas similares, lo que es útil aquí, diferencia entre kotlin también, aplicar, dejar, usar, tomar y tomar a menos que en Kotlin