Kurz: fun quadrat(x: Int) = x * x // Ausdruckskörper, Typ wird erschlossen
Teil des Kurses Kotlin
Funktionen definieren
fun addiere(a: Int, b: Int): Int {
return a + b
}
fun quadrat(x: Int) = x * x // Ausdruckskörper, Typ wird erschlossen
fun gruss(name: String = "Welt", anrede: String = "Hallo"): String = "$anrede, $name!"
fun protokolliere(text: String) { // Unit = kein Rückgabewert (wie void)
println("[LOG] $text")
}
fun summe(vararg zahlen: Int): Int = zahlen.sum()
fun minMax(liste: List<Int>): Pair<Int, Int> = Pair(liste.min() ?: 0, liste.max() ?: 0)
fun main() {
println(addiere(2, 3))
println(quadrat(7))
println(gruss())
println(gruss("Mia"))
println(gruss(anrede = "Hi", name = "Tom")) // benannte Argumente
protokolliere("gestartet")
println(summe(1, 2, 3, 4))
val zahlen = intArrayOf(5, 6)
println(summe(*zahlen)) // Spread-Operator *
val (klein, gross) = minMax(listOf(4, 9, 1)) // Destrukturierung
println("$klein $gross")
}Ausgabe:
5
49
Hallo, Welt!
Hallo, Mia!
Hi, Tom!
[LOG] gestartet
10
11
1 9Standardwerte und benannte Argumente ersetzen die meisten überladenen Funktionen.
Lokale Funktionen und Rekursion
fun fakultaet(n: Int): Long = if (n <= 1) 1 else n * fakultaet(n - 1)
fun fibonacci(n: Int): List<Int> {
fun naechste(a: Int, b: Int) = b to a + b // lokale Funktion
var paar = 0 to 1
val ergebnis = mutableListOf<Int>()
repeat(n) {
ergebnis.add(paar.first)
paar = naechste(paar.first, paar.second)
}
return ergebnis
}
tailrec fun ggt(a: Int, b: Int): Int = if (b == 0) a else ggt(b, a % b) // Endrekursion: keine Stapelüberläufe
fun main() {
println(fakultaet(10))
println(fibonacci(10))
println(ggt(48, 18))
}Ausgabe:
3628800
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
6Funktionstypen und Lambdas
Funktionen sind Werte. Ein Funktionstyp wird als (Parameter) -> Rückgabe geschrieben:
fun anwenden(x: Int, f: (Int) -> Int): Int = f(x)
fun multiplikator(faktor: Int): (Int) -> Int = { x -> x * faktor }
fun main() {
val verdopple: (Int) -> Int = { it * 2 }
val plus: (Int, Int) -> Int = { a, b -> a + b }
println(verdopple(21))
println(plus(3, 4))
println(anwenden(5) { it + 1 }) // Lambda außerhalb der Klammern
println(anwenden(5, ::quadrat)) // Funktionsreferenz
println(multiplikator(3)(7))
var zaehler = 0
val erhoehe = { zaehler++ } // Closure verändert äußere Variable
erhoehe(); erhoehe()
println(zaehler)
}
fun quadrat(x: Int) = x * xAusgabe:
42
7
6
25
21
2Hat ein Lambda genau einen Parameter, heißt er automatisch it. Ist das Lambda das letzte Argument, steht es hinter den Klammern (trailing lambda).
Erweiterungsfunktionen
Du kannst bestehende Typen um Funktionen erweitern, ohne sie zu verändern:
fun String.istPalindrom(): Boolean {
val sauber = this.toLowerCase().filter { it.isLetter() }
return sauber == sauber.reversed()
}
fun Int.istGerade() = this % 2 == 0
fun <T> List<T>.zweites(): T? = if (size >= 2) this[1] else null
val Int.quadrat: Int get() = this * this // Erweiterungs-Property
fun main() {
println("Anna".istPalindrom())
println("A man, a plan, a canal: Panama".istPalindrom())
println(4.istGerade())
println(listOf(1, 2, 3).zweites())
println(emptyList<Int>().zweites())
println(7.quadrat)
}Ausgabe:
true
true
true
2
null
49Infix, Operatoren und inline
infix fun Int.hoch(n: Int): Long {
var r = 1L
repeat(n) { r *= this }
return r
}
data class Vektor(val x: Int, val y: Int) {
operator fun plus(o: Vektor) = Vektor(x + o.x, y + o.y)
operator fun times(k: Int) = Vektor(x * k, y * k)
operator fun get(i: Int) = if (i == 0) x else y
}
inline fun messe(block: () -> Unit): Boolean { // inline: Lambda wird eingefügt (schneller)
block()
return true
}
fun main() {
println(2 hoch 10)
val v = Vektor(1, 2) + Vektor(3, 4) * 2
println(v)
println(v[0])
println(messe { println("im Block") })
}Ausgabe:
1024
Vektor(x=7, y=10)
7
im Block
trueMerke
fun name(p: Typ = std): Rückgabetyp; Ausdruckskörper= ausdruck- Standardwerte, benannte Argumente,
varargund*(Spread) - Lambdas
{ x -> ... }/it; Funktionstypen(Int) -> Int; Referenzen::name - Erweiterungsfunktionen
fun String.foo() tailrec,infix,operator,inlinefür Spezialfälle
Übungsaufgabe
Schreibe eine Erweiterungsfunktion List<Int>.mittelwert() und eine Funktion, die ein Lambda auf jedes Element anwendet.
Quiz zur Selbstkontrolle
Was ist Unit?
- Der Rückgabetyp für “kein Wert” (wie void) (richtig)
- Eine Zahl
- Ein Test
- Ein Paket
Wie heißt der implizite Parameter eines Lambdas mit einem Parameter?
- it (richtig)
- this
- arg
- x
Wozu dienen Erweiterungsfunktionen?
- Bestehende Typen um Funktionen erweitern, ohne sie zu ändern (richtig)
- Klassen zu vererben
- Threads zu starten
- Code zu verschlüsseln
Weiter im Kurs
Zurück: Strings und Kontrollfluss
Weiter: Null-Sicherheit
Alle Kapitel: Kotlin im Überblick