0Pricing
Kotlin Academy · Aula

Variância no Local da Declaração

in e out

Variância no Local da Declaração é uma aula grátis de Kotlin Academy no CoddyKit. Esta é a aula 2 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Kotlin Academy, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Kotlin Academy inclui 4 aulas no total.

O problema da variância

Uma List<String> é um tipo de List<Any>? Às vezes sim, às vezes não. A variância descreve como os tipos genéricos se relacionam quando seus parâmetros de tipo se relacionam. O Kotlin usa out e in para expressar isso.

Invariância por padrão

Por padrão, os genéricos são invariantes: Box<String> NÃO é um Box<Any>, embora String seja um subtipo de Any. Isso impede operações inseguras.

class Box<T>(val value: T)

fun main() {
    val strBox = Box("hi")
    // val anyBox: Box<Any> = strBox // would not compile
    println(strBox.value)
}

Covariância com out

Marcar um parâmetro de tipo com out faz com que ele seja covariante: Producer<String> se torna um subtipo de Producer<Any>. O tipo só pode aparecer em posições de saída, como tipos de retorno.

class Producer<out T>(private val item: T) {
    fun produce(): T = item
}

fun main() {
    val strProducer: Producer<String> = Producer("hello")
    val anyProducer: Producer<Any> = strProducer
    println(anyProducer.produce())
}

Por que out é seguro

Se uma classe apenas produz, ou retorna, T e nunca o consome, tratar uma Producer<String> como uma Producer<Any> é seguro, pois cada String que ela retorna também é um Any.

out na biblioteca padrão

A List<out E> somente leitura do Kotlin é covariante, por isso uma List<String> pode ser usada onde uma List<Any> é esperada.

fun printAll(items: List<Any>) {
    items.forEach { println(it) }
}

fun main() {
    val names: List<String> = listOf("Ann", "Bob")
    printAll(names)
}

Contravariância com in

Marcar um parâmetro de tipo com in faz com que ele seja contravariante: Consumer<Any> se torna um subtipo de Consumer<String>. O tipo só pode aparecer em posições de entrada, como parâmetros.

class Consumer<in T> {
    fun consume(item: T) {
        println("Consumed $item")
    }
}

fun main() {
    val anyConsumer: Consumer<Any> = Consumer()
    val strConsumer: Consumer<String> = anyConsumer
    strConsumer.consume("hi")
}

Por que in é seguro

Um consumidor que aceita Any certamente pode aceitar uma String. Portanto, uma Consumer<Any> pode ser usada em qualquer lugar onde uma Consumer<String> seja necessária.

A mnemônica PECS

Lembre-se de Producer Extends, Consumer Super ou, nos termos do Kotlin: out para produtores, isto é, saída, e in para consumidores, isto é, entrada. Um tipo que apenas produz T usa out; um tipo que apenas recebe T usa in.

Combinando in e out

Um parâmetro de tipo usado tanto para entrada quanto para saída, como em uma lista mutável, deve permanecer invariante. Os tipos Function mostram os dois casos: os parâmetros são in e o retorno é out.

fun main() {
    val f: (Number) -> Int = { it.toInt() }
    val g: (Int) -> Number = f
    println(g(3.0.let { Number::class; 5 }))
}

Variância no local da declaração significa um único lugar

A variância no local da declaração é definida uma vez, na própria classe, com in/out. Todas as utilizações da classe recebem a variância automaticamente, ao contrário do Java, em que você repete os curingas em cada utilização.

Escolhendo in ou out

Pergunte: esta classe apenas produz T, usando out; apenas consome T, usando in; ou faz as duas coisas, devendo permanecer invariante? Associar o modificador à função da classe torna seus tipos genéricos flexíveis e seguros.

Verificação rápida

O que o modificador out indica?

Recapitulação

Por padrão, os genéricos são invariantes. Use out para obter covariância quando um tipo apenas produz valores e in para obter contravariância quando ele apenas consome valores. Lembre-se: produtores usam out, consumidores usam in. Em seguida, você aplicará a variância no ponto de uso com projeções de tipo.

Perguntas Frequentes

A aula “Variância no Local da Declaração” é grátis?

Sim — o texto completo de “Variância no Local da Declaração” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Kotlin Academy, atualize para CoddyKit PRO. O curso de Kotlin Academy inclui 4 aulas no total.

O que vou aprender em “Variância no Local da Declaração”?

in e out Você pratica Kotlin Academy com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.

Preciso ter experiência prévia para começar Kotlin Academy?

Nenhuma experiência prévia é necessária. Kotlin Academy no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 2 de 4.

Quanto tempo leva a aula “Variância no Local da Declaração”?

A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.

Posso escrever e executar código nesta aula de Kotlin Academy?

Sim. Cada aula de Kotlin Academy inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.

Todas as aulas deste curso

  1. Funções e Classes Genéricas
  2. Variância no Local da Declaração
  3. Variância no Local de Uso
  4. Restrições Genéricas
← Voltar para Kotlin Academy