Menu
Coddy logo textTech

Generische Funktionen

Teil des Abschnitts Objektorientierte Programmierung der Kotlin-Journey von Coddy. Lektion 37 von 57.

Eine generische Funktion funktioniert mit jedem Typ. Ihr Typparameter, der vor dem Funktionsnamen in spitzen Klammern geschrieben wird, steht für den Typ, den der Aufrufer verwendet. T ist die übliche Bezeichnung:

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

Innerhalb von main:

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

Ausgabe:

4
NONE

Kotlin leitet das Typargument aus den Argumenten ab. Wenn es nichts gibt, aus dem es abgeleitet werden kann, schreibst du es selbst, wie oben bei listOf<String>():

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

Innerhalb von main:

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

Ausgabe:

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

Eine Funktion kann mehrere Typparameter haben, und ein Funktionstyp-Parameter kann sie verwenden. So funktionieren Bibliotheksfunktionen wie map für jeden Element- und Ergebnistyp:

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 }

Innerhalb von main:

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

Ausgabe:

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

Ein Typparameter behält den Typ des Aufrufers bei. firstOr(listOf(3, 5), 0) gibt ein Int zurück, daher wird + 1 kompiliert. Eine für List<Any> geschriebene Version würde ebenfalls jede Liste akzeptieren, aber sie würde Any zurückgeben und bei jedem Aufruf eine Typumwandlung erzwingen:

fun firstAny(list: List<Any>, default: Any): Any = if (list.isEmpty()) default else list[0]
// firstAny(listOf(3, 5), 0) + 1               // Fehler: Any hat kein plus
(firstAny(listOf(3, 5), 0) as Int) + 1         // kompiliert, benötigt aber einen Cast
firstOr(listOf(3, 5), 0) + 1                   // generisch: das Ergebnis ist ein Int
challenge icon

Aufgabe

Einfach

Schreibe zwei generische Funktionen, die mit Listen beliebigen Typs arbeiten. countWhere(items, predicate) gibt zurück, wie viele Elemente das Prädikat erfüllen, eine Funktion (T) -> Boolean. mostCommon(items) gibt das Element zurück, das am häufigsten vorkommt (bei gleicher Anzahl dasjenige, das zuerst in der Liste erscheint), oder null für eine leere Liste.

Der bereitgestellte Code liest eine Zeile mit Wörtern und eine Zeile mit Zahlen ein und gibt die Anzahl der Wörter mit mehr als 3 Buchstaben, das häufigste Wort, die Anzahl der geraden Zahlen, die häufigste Zahl sowie nothing: null für eine leere Liste aus.

Dein Code gehört in ListTools.kt. Main.kt enthält den bereitgestellten Eingabe-/Ausgabecode und darf nicht bearbeitet werden.

Probier es selbst

fun main() {
    // Bereitgestellter Ein-/Ausgabe-Code: belasse ihn wie er ist
    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 dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Objektorientierte Programmierung

Übe selbstständig: Kotlin-Playground