Menu
Coddy logo textTech

Classes genéricas

Parte da seção Programação Orientada a Objetos do Journey de Kotlin da Coddy. Lição 38 de 57.

Uma classe também pode ter parâmetros de tipo. Box<T> armazena um valor de qualquer tipo, e cada instância fixa o tipo: uma Box<Int> aceita apenas valores Int:

class Box<T>(var value: T) {
    fun describe() = "box with $value"
}

Dentro de main:

val numberBox = Box(42)
val textBox = Box("hello")
numberBox.value += 1
println(numberBox.describe())
println(textBox.describe())
// numberBox.value = "x"   // erro: um String não é um Int

Saída:

box with 43
box with hello

Contêineres são as classes genéricas típicas. Uma implementação de Stack<T> funciona para todos os tipos de elementos, e o compilador verifica o que entra e o que sai:

class Stack<T> {
    private val items = mutableListOf<T>()
    val size: Int
        get() = items.size

    fun push(item: T) { items.add(item) }
    fun pop(): T? = items.removeLastOrNull()
    fun peek(): T? = items.lastOrNull()
}

Dentro de main:

val stack = Stack<String>()
stack.push("a")
stack.push("b")
println(stack.pop())
println(stack.peek())
println(stack.size)

Saída:

b
a
1

O argumento de tipo é inferido a partir dos argumentos do construtor quando há algum, como em Box(42). Caso contrário, escreva-o: Stack<String>(). Instâncias com argumentos de tipo diferentes são tipos diferentes, portanto uma Stack<String> nunca é confundida com uma Stack<Int>. As funções de uma classe genérica também podem adicionar seus próprios parâmetros de tipo:

class Box<T>(val value: T) {
    fun <R> map(f: (T) -> R): Box<R> = Box(f(value))
}

Dentro de main:

val length = Box("kotlin").map { it.length }
println(length.value + 1)

Saída:

7

As interfaces genéricas seguem as mesmas regras. Uma classe pode implementar uma interface genérica ou para um argumento de tipo específico:

interface Repository<T> {
    fun add(item: T)
    fun all(): List<T>
}
class MemoryRepository<T> : Repository<T> {
    private val items = mutableListOf<T>()
    override fun add(item: T) { items.add(item) }
    override fun all() = items.toList()
}
class TagRepository : Repository<String> {
    private val tags = sortedSetOf<String>()
    override fun add(item: String) { tags.add(item.lowercase()) }
    override fun all() = tags.toList()
}

Dentro de main:

val ids = MemoryRepository<Int>()
ids.add(3); ids.add(1)
val tags = TagRepository()
tags.add("Kotlin"); tags.add("JVM")
println("${ids.all()} ${tags.all()}")

Saída:

[3, 1] [jvm, kotlin]
challenge icon

Desafio

Fácil

Escreva a classe genérica History<T>(limit) que se lembra dos últimos limit itens. add(item) adiciona um item ao final e remove o mais antigo quando há mais de limit. latest é o item mais recente ou null, e all() retorna os itens do mais antigo ao mais recente como uma lista somente para leitura. Em seguida, escreva a extensão History<Int>.average(), que existe apenas para históricos de números e retorna a média inteira dos números mantidos (0 quando vazio).

O código fornecido lê o limite, uma linha de palavras e uma linha de números. Ele preenche um History<String> e um History<Int> e imprime as palavras mantidas, a palavra mais recente, os números mantidos, a média deles e empty latest: null.

Seu código deve ser colocado em History.kt. Main.kt contém o código fornecido de entrada/saída e não pode ser editado.

Experimente você mesmo

fun main() {
    // Código de entrada/saída fornecido: mantenha-o como está
    val input = generateSequence(::readLine).toList()
    val limit = input[0].toInt()
    val words = History<String>(limit)
    for (w in input[1].split(" ")) words.add(w)
    val numbers = History<Int>(limit)
    for (n in input[2].split(" ")) numbers.add(n.toInt())
    println("words: ${words.all()}")
    println("latest word: ${words.latest}")
    println("numbers: ${numbers.all()}")
    println("average: ${numbers.average()}")
    println("empty latest: ${History<Char>(3).latest}")
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos

Pratique por conta própria: Playground de Kotlin