Middle
¿Cómo trabajar con tipos genéricos en Kotlin?
sobes.tech AI
Respuesta de la IA
Los tipos genéricos en Kotlin permiten crear clases, interfaces y funciones que trabajan con datos de diferentes tipos, manteniendo la seguridad de tipos en tiempo de compilación.
Conceptos básicos y formas de trabajo:
- Declaración de clases e interfaces genéricas:
class Box<T>(val item: T) // Clase genérica con parámetro de tipo T interface MyList<E> { // Interfaz genérica con parámetro de tipo E fun add(element: E) fun get(index: Int): E } - Declaración de funciones genéricas:
fun <T> printAnything(value: T) { // Función genérica con parámetro de tipo T println(value) } - Creación de instancias de tipos genéricos:
val intBox: Box<Int> = Box(123) // Especificación de un tipo concreto (Int) val stringBox = Box("hello") // El compilador infiere el tipo (String) - Variantes: Permite definir cómo funcionan los subtipos con tipos genéricos.
- Covarianza (out): Permite usar el tipo y sus subtipos. Se indica con
out. Ejemplo:List<out Any>puede contenerList<String>. Se usa para tipos que producen valores (por ejemplo, lectura de colecciones).interface Producer<out T> { // out T - parámetro covariante fun produce(): T } - Contravarianza (in): Permite usar el tipo y sus supertipos. Se indica con
in. Ejemplo:Comparator<in String>puede trabajar conComparator<Any>. Se usa para tipos que consumen valores (por ejemplo, escritura en colecciones).interface Consumer<in T> { // in T - parámetro contravariante fun consume(value: T) } - Invarianza: El tipo en el parámetro genérico debe ser exactamente el mismo. Este es el comportamiento por defecto.
- Covarianza (out): Permite usar el tipo y sus subtipos. Se indica con
- Restricciones de tipos (
where): Permite limitar el tipo del parámetro para que implemente ciertas interfaces o herede de una clase específica.fun <T : Comparable<T>> max(a: T, b: T): T { // T debe implementar Comparable return if (a > b) a else b } fun <T> process(item: T) where T : Runnable, T : Comparable<T> { item.run() // ... uso de comparabilidad } - Proyección estrella (
*): Se usa cuando no importan los argumentos específicos del tipo. Similar a<?>en Java.fun printList(list: List<*>) { // Puede aceptar una lista de cualquier tipo for (item in list) { println(item) } }
Los tipos genéricos en Kotlin usan eliminación de tipos (type erasure), como en Java. La información sobre tipos específicos se pierde en tiempo de ejecución. Para trabajar con tipos en tiempo de ejecución, se usan tipos reificados.
- Tipos reificados (
reified): Solo disponibles en funciones inline. Permiten mantener la información del tipo del parámetro en tiempo de ejecución.inline fun <reified T> checkType(value: Any) { // T - tipo reificado if (value is T) { println("El valor es del tipo T") } else { println("El valor no es del tipo T") } }