Middle
Como trabalhar com tipos genéricos em Kotlin?
sobes.tech IA
Resposta da IA
Os tipos genéricos em Kotlin permitem criar classes, interfaces e funções que trabalham com dados de diferentes tipos, mantendo a segurança de tipos durante a compilação.
Conceitos principais e formas de trabalhar:
- Declaração de classes e interfaces genéricas:
class Box<T>(val item: T) // Classe genérica com parâmetro de tipo T interface MyList<E> { // Interface genérica com parâmetro de tipo E fun add(element: E) fun get(index: Int): E } - Declaração de funções genéricas:
fun <T> printAnything(value: T) { // Função genérica com parâmetro de tipo T println(value) } - Criação de instâncias de tipos genéricos:
val intBox: Box<Int> = Box(123) // Especificação de um tipo concreto (Int) val stringBox = Box("hello") // O compilador infere o tipo (String) - Variações: Permite definir como funcionam os subtipos com tipos genéricos.
- Covariância (out): Permite usar o tipo e seus subtipos. Indicado por
out. Exemplo:List<out Any>pode conterList<String>. Usado para tipos que produzem valores (por exemplo, leitura de coleções).interface Producer<out T> { // out T - parâmetro covariante fun produce(): T } - Contravariância (in): Permite usar o tipo e seus supertipos. Indicado por
in. Exemplo:Comparator<in String>pode trabalhar comComparator<Any>. Usado para tipos que consomem valores (por exemplo, escrita em coleções).interface Consumer<in T> { // in T - parâmetro contravariante fun consume(value: T) } - Invariância: O tipo no parâmetro genérico deve ser exatamente o mesmo. Este é o comportamento padrão.
- Covariância (out): Permite usar o tipo e seus subtipos. Indicado por
- Restrições de tipos (
where): Permite limitar o tipo do parâmetro para que implemente certas interfaces ou herde de uma classe específica.fun <T : Comparable<T>> max(a: T, b: T): T { // T deve implementar Comparable return if (a > b) a else b } fun <T> process(item: T) where T : Runnable, T : Comparable<T> { item.run() // ... uso de comparabilidade } - Projeção estrela (
*): Usada quando não importa o argumento específico do tipo. Semelhante a<?>em Java.fun printList(list: List<*>) { // Pode aceitar uma lista de qualquer tipo for (item in list) { println(item) } }
Os tipos genéricos em Kotlin usam eliminação de tipos (type erasure), como em Java. A informação sobre tipos específicos é perdida em tempo de execução. Para trabalhar com tipos em tempo de execução, usam-se tipos reificados.
- Tipos reificados (
reified): Disponíveis apenas para funções inline. Permitem manter a informação do tipo do parâmetro em tempo de execução.inline fun <reified T> checkType(value: Any) { // T - tipo reificado if (value is T) { println("Valor é do tipo T") } else { println("Valor não é do tipo T") } }