Menu
Coddy logo textTech

Fonctions génériques

Fait partie de la section Programmation orientée objet du Journey Kotlin de Coddy. Leçon 37 sur 57.

Une fonction générique fonctionne avec n’importe quel type. Son paramètre de type, écrit entre chevrons avant le nom de la fonction, représente le type utilisé par l’appelant. T est le nom habituel :

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

Dans main :

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

Sortie :

4
NONE

Kotlin déduit l’argument de type à partir des arguments. Lorsqu’il n’y a rien à partir de quoi le déduire, vous l’écrivez vous-même, comme dans listOf<String>() ci-dessus :

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

À l’intérieur de main :

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

Sortie :

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

Une fonction peut avoir plusieurs paramètres de type, et un paramètre de type fonction peut les utiliser. C’est ainsi que les fonctions de bibliothèque telles que map fonctionnent avec chaque type d’élément et de résultat :

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 }

Dans main :

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

Sortie :

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

Un paramètre de type conserve le type de l’appelant. firstOr(listOf(3, 5), 0) renvoie un Int, donc + 1 est compilé. Une version écrite pour List<Any> accepterait également toutes les listes, mais elle renverrait Any et imposerait une conversion de type à chaque appel :

fun firstAny(list: List<Any>, default: Any): Any = if (list.isEmpty()) default else list[0]
// firstAny(listOf(3, 5), 0) + 1               // erreur : Any n'a pas de plus
(firstAny(listOf(3, 5), 0) as Int) + 1         // compile, mais nécessite un cast
firstOr(listOf(3, 5), 0) + 1                   // générique : le résultat est un Int
challenge icon

Défi

Facile

Écrivez deux fonctions génériques qui fonctionnent avec des listes de n’importe quel type. countWhere(items, predicate) renvoie le nombre d’éléments qui satisfont le prédicat, une fonction (T) -> Boolean. mostCommon(items) renvoie l’élément qui apparaît le plus souvent (celui qui apparaît en premier dans la liste lorsque les occurrences sont à égalité), ou null pour une liste vide.

Le code fourni lit une ligne de mots et une ligne de nombres, puis affiche le nombre de mots de plus de 3 lettres, le mot le plus fréquent, le nombre de nombres pairs, le nombre le plus fréquent et nothing: null pour une liste vide.

Votre code doit se trouver dans ListTools.kt. Main.kt contient le code fourni d’entrée/sortie et ne peut pas être modifié.

Essayez vous-même

fun main() {
    // Code d'entrée/sortie fourni : le garder tel quel
    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 iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Programmation orientée objet

Entraînez-vous par vous-même : Playground Kotlin