Muy buenas, soy Luis y para hoy les traigo otro nuevo tutorial.
Kotlin ha ganado una popularidad considerable en los últimos años. La naturaleza multiplataforma y la interoperabilidad con Java y JVM han aumentado la adaptabilidad y aceptación de la comunidad de desarrolladores.
Además, el primer enfoque de Kotlin por parte de Google atrajo a los desarrolladores de Android para adaptarlo.
Tengo la intención de crear una serie de conceptos simplificados de Kotlin que me ayudaron a dominar Kotlin:
Índice
La covarianza y la contravarianza
Al igual que en Java, Kotlin también admite genéricos que nos permiten operar en un método u objeto sin proporcionar el tipo real en tiempo de compilación junto con la seguridad de tipos.
out
(covarianza) y in
(contravarianza).Debajo del capó es tan simple como a continuación:
A
es padre / superclase y B
es hijo / subclase.open class A { //some methods & member variable }class B : A() { // some mehods & member variables }
Significa que puede utilizar un subtipo en lugar de un supertipo.
Tomemos un ejemplo:
class GenericClass<T: A>{ // some actions to be done for GenericClass }
Ahora, si intentas hacer algo como:
val genericClass:GenericClass<A> = GenericClass<B>()
Obtendrá un error de compilación TypeMismatch
.
Ahora si cambiamos:
class GenericClass<out T: A>{ // some actions to be done for GenericClass }
La declaración se compilará correctamente.
Algunas reglas para la covarianza cuando un tipo genérico de clase o interfaz tiene el prefijo out
:
- Solo se puede utilizar en una posición «fuera», como un tipo de retorno de función.
- También se puede utilizar como
val
propiedad. - No se puede utilizar como
var
entrada de propiedad o función.
Toda la interfaz de colección en Kotlin tiene un tipo genérico definido con out
.
Contravarianza
Significa que puede usar supertipo en lugar de un subtipo
Tomemos un ejemplo:
class GenericClass<T: A>{ // some actions to be done for GenericClass }
Ahora, si intentas hacer algo como:
val genericClass:GenericClass<B> = GenericClass<A>()
obtendrá un error de compilación TypeMismatch
Ahora si cambiamos
class GenericClass<in T: A>{ // some actions to be done for GenericClass }
La declaración se compilará correctamente.
Algunas reglas para la contravarianza cuando un tipo genérico de clase o interfaz tiene el prefijo in
:
- Solo se puede utilizar en una posición «in» , como el tipo de entrada de función.
- No se puede utilizar como posición de “out” , es decir no se pueden usar como
val
o la propiedadvar
.
inline
función
Kotlin proporciona una alta flexibilidad y reutilización a través de funciones de orden superior que toman una lambda como parámetro de entrada. Sin embargo, esto viene con una pequeña penalización en términos de rendimiento.
Cuando declaras una lambda, se trata como un objeto normal en Java. Esto significa que tendrá su memoria asignada para todas las variables utilizadas dentro de la lambda y así sucesivamente.
Por ejemplo, declaramos una función de orden superior de la siguiente manera:
fun printSalutation(message: (String) -> String) println(message("MR"))
Luego invocas la función:
fun test() printSalutation "Hello $it Foo. How are you?"
public final void printSalutation(@NotNull Function1 message) Intrinsics.checkParameterIsNotNull(message, "message"); Object var2 = message.invoke("MR"); boolean var3 = false; System.out.println(var2); public final void test() this.printSalutation((Function1)null.INSTANCE);
Si lo nota, crea una instancia adicional y la pasa a printSalutation
.
Puede generar esto usando Android Studio de la siguiente manera:
Tools → Kotlin → Show kotlin byte code → Decompile
Luego, desde la ventana de la derecha, seleccione Decompile
Puede mitigar fácilmente esta sobrecarga utilizando inline
función que elimina la necesidad de usar una instancia de objeto y realizar asignaciones de memoria variable para el lambda.
Es tan simple como prefijar inline
palabra clave a la función de la siguiente manera:
inline fun printSalutation(message: (String) -> String) println(message("MR"))
Esta vez, cuando descompila el código:
public final void printSalutation(@NotNull Function1 message) int $i$f$printSalutation = 0; Intrinsics.checkParameterIsNotNull(message, "message"); Object var3 = message.invoke("MR"); boolean var4 = false; System.out.println(var3); public final void test() int $i$f$printSalutation = false; String it = "MR"; int var4 = false; it = "Hello " + it + " Foo. How are you?"; var4 = false; System.out.println(it); }
Como puede observar cuando antepone una función con inline
el código generado elimina la llamada y la reemplaza con el contenido de la función lambda, lo que elimina la sobrecarga y hace que el código se ejecute más rápido.
- Covarianza: Utilice un subtipo en lugar de un supertipo.
- Contravarianza: Use supertipo en lugar de un subtipo
- función en línea: Mejore el impacto en el rendimiento causado por la función de orden superior.
Espero que te haya sido de utilidad. Gracias por leer este post.
Añadir comentario