Menu
Coddy logo textTech

Funções genéricas

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

Uma função genérica funciona com qualquer tipo. Seu parâmetro de tipo, escrito entre sinais de menor e maior antes do nome da função, representa o tipo usado pelo chamador. T é o nome usual:

fun <T> firstOr(list: List<T>, default: T): T = if (list.isEmpty()) default else list[0]

Dentro de main:

println(firstOr(listOf(3, 5), 0) + 1)
println(firstOr(listOf<String>(), "none").uppercase())

Saída:

4
NONE

O Kotlin infere o argumento de tipo a partir dos argumentos. Quando não há nada a partir do qual inferi-lo, você mesmo o escreve, como em listOf<String>() acima:

fun <T> repeatItem(item: T, times: Int): List<T> = List(times) { item }

Dentro de main:

println(repeatItem("ab", 3))
println(repeatItem(7, 2))
val empty = repeatItem<Double>(1.5, 0)
println(empty)

Saída:

[ab, ab, ab]
[7, 7]
[]

Uma função pode ter vários parâmetros de tipo, e um parâmetro de tipo função pode usá-los. É assim que funções de biblioteca como map funcionam para cada tipo de elemento e de resultado:

fun <A, B> transform(items: List<A>, f: (A) -> B): List<B> {
    val out = mutableListOf<B>()
    for (item in items) out.add(f(item))
    return out
}

fun <K, V> invert(map: Map<K, V>): Map<V, K> = map.entries.associate { (k, v) -> v to k }

Dentro de main:

println(transform(listOf("kiwi", "fig")) { it.length })
println(invert(mapOf("a" to 1, "b" to 2)))

Saída:

[4, 3]
{1=a, 2=b}

Um parâmetro de tipo preserva o tipo do chamador. firstOr(listOf(3, 5), 0) retorna um Int, então + 1 compila. Uma versão escrita para List<Any> também aceitaria qualquer lista, mas retornaria Any e exigiria uma conversão em cada chamada:

fun firstAny(list: List<Any>, default: Any): Any = if (list.isEmpty()) default else list[0]
// firstAny(listOf(3, 5), 0) + 1               // erro: Any não tem plus
(firstAny(listOf(3, 5), 0) as Int) + 1         // compila, mas precisa de um cast
firstOr(listOf(3, 5), 0) + 1                   // genérico: o resultado é um Int
challenge icon

Desafio

Fácil

Escreva duas funções genéricas que funcionem para listas de qualquer tipo. countWhere(items, predicate) retorna quantos elementos passam pelo predicado, uma função (T) -> Boolean. mostCommon(items) retorna o elemento que aparece com mais frequência (aquele que aparece primeiro na lista quando há empate nas contagens), ou null para uma lista vazia.

O código fornecido lê uma linha de palavras e uma linha de números, e imprime o número de palavras com mais de 3 letras, a palavra mais comum, o número de números pares, o número mais comum e nothing: null para uma lista vazia.

Seu código deve estar em ListTools.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 words = input[0].split(" ")
    val numbers = input[1].split(" ").map { it.toInt() }
    println("long words: ${countWhere(words) { it.length > 3 }}")
    println("most common word: ${mostCommon(words)}")
    println("even numbers: ${countWhere(numbers) { it % 2 == 0 }}")
    println("most common number: ${mostCommon(numbers)}")
    println("nothing: ${mostCommon(listOf<String>())}")
}
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