Sobes.tech
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 conter List<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 com Comparator<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.
  • 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")
        }
    }