Sobes.tech
Junior

Que tipos de genéricos conhece?

sobes.tech IA

Resposta da IA

Invariantes, covariantes e contravariantes.

  • Invariância: O tipo List<A> não é um subtipo de List<B> e vice-versa, mesmo que A seja um subtipo de B. O tipo mantém-se exatamente.
  • Covariância (out): Permite usar subtipos. List<A> é um subtipo de List<B> se A for um subtipo de B. Usado para parâmetros de saída (valores devolvidos).
fun foo(list: List<out Number>) {
    // Pode ler da lista (Number, Double, Int, etc.)
    val number: Number = list[0]
    // Não pode adicionar à lista (não se sabe que tipo de elementos se espera)
    // list.add(1) // Erro de compilação
}
  • Contravariância (in): Permite usar supertipos. List<B> é um subtipo de List<A> se A for um subtipo de B. Usado para parâmetros de entrada (argumentos).
fun foo(comparable: Comparable<in String>) {
    // Pode passar argumentos String (ou seus supertipos)
    val result = comparable.compareTo("hello")
    // Não pode obter resultados do tipo String (não se sabe que tipo de resultado)
    // val str: String = comparable.compareTo("world") // Erro de compilação
}

Em Kotlin, estes conceitos são implementados com as anotações out e in nos parâmetros de tipo. Em Java, usa-se wildcards (? extends para covariância e ? super para contravariância).

Tipo Propósito Palavra-chave (Kotlin) Wildcard (Java) Leitura permitida Escrita permitida
Invariante Correspondência exata de tipo Não Não Sim Sim
Covariante Uso de subtipos (produtor - "out") out ? extends T Sim Não
Contravariante Uso de supertipos (consumidor - "in") in ? super T Não Sim