Antes de empezar este post tal vez sería bueno que leas este post antes :D
Scala permite definir colecciones y estructuras de datos genéricas, pero a veces no necesitamos saber con precisión qué tipo contienen, o simplemente queremos permitir varios tipos relacionados. Para esos casos existen los tipos genéricos anónimos, representados por el underscore (_).
Un tipo genérico anónimo en Scala se escribe con un guion bajo (_) en lugar de especificar un tipo concreto. Es útil cuando:
- No necesitás conocer el tipo exacto.
- Queremos aceptar varios subtipos o supertypos.
Veamos un ejemplo:
Lista de cualquier tipo (wildcard total)
val lista: List[_] = List(1, "hola", true)
Esto indica que lista es de algún tipo List[T], pero no importa cuál es T.
Subtipado: _ <: Tipo
Permite aceptar cualquier subtipo del tipo dado (covarianza).
class Animal
class Perro extends Animal
class Gato extends Animal
val animales: List[_ <: Animal] = List(new Perro, new Gato)
Esto significa: una lista de algo que es subtipo de Animal.
Supertyping: _ >: Tipo
Permite aceptar cualquier supertipo del tipo dado (contravarianza).
val cosas: List[_ >: Perro] = List(new Animal, new Perro)
Esto significa: una lista de algo que es supertipo de Perro.
Y ¿Por qué usar genéricos anónimos?
- Cuando escribís funciones genéricas que pueden aceptar muchos tipos.
- Para asegurar compatibilidad con estructuras covariantes/contravariantes.
- Para restringir o abrir el tipo de manera controlada.
Los tipos anónimos no te permiten hacer mucho con los elementos (no podés acceder a sus métodos específicos), porque Scala no sabe exactamente qué tipo hay.
val lista: List[_] = List("hola", "chau")
// lista(0).toUpperCase() // ERROR: no se puede garantizar el tipo
En Java existe el signo de pregunta para esto (?):
List<?> lista;
List<? extends Animal> subtipos;
List<? super Perro> supertypos;
En Scala es más limpio y expresivo:
List[_]
List[_ <: Animal]
List[_ >: Perro]
Los tipos genéricos anónimos en Scala te permiten trabajar con estructuras de datos más genéricas y flexibles, especialmente en APIs o librerías donde no se necesita o no se conoce el tipo exacto. Son ideales para mantener la seguridad de tipos sin perder generalidad.