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 IntSaída:
box with 43
box with helloContê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
1O 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:
7As 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]Desafio
FácilEscreva 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}")
}
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
1Classes e Objetos
Trabalhando com ArquivosDefinindo ClassesConstrutores PrimáriosBlocos init e ValidaçãoConstrutores SecundáriosRecapitulação - Cartão da Biblioteca4Herança
Classes Abertas e SubclassesSobrescrevendo Membrossuper e ConstrutoresClasses AbstratasRevisão - Diretório de Funcionários2Propriedades e Encapsulamento
Acessores PersonalizadosModificadores de VisibilidadeSetters Privadoslazy e lateinitRevisão - Conta Bancária5Interfaces
Declarando InterfacesMétodos PadrãoMúltiplas InterfacesInterfaces como TiposRecapitulação - Métodos de Pagamento8Genéricos
Funções genéricasClasses genéricasRestrições de tipoVariância com in e outRecapitulação - Fila de prioridade11Projeto: Gerenciamento de Biblioteca
Livros e MembrosEmpréstimo de LivrosPratique por conta própria: Playground de Kotlin