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")
}5 49 Hallo, Welt! Hallo, Mia! Hi, Tom! [LOG] gestartet 10 11 1 9
Standardwerte 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))
}3628800 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34] 6
Funktionstypen 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 * x42 7 6 25 21 2
Hat 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)
}true true true 2 null 49
Infix, 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") })
}1024 Vektor(x=7, y=10) 7 im Block true
Merke
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
Aufgabe
Schreibe eine Erweiterungsfunktion List<Int>.mittelwert() und eine Funktion, die ein Lambda auf jedes Element anwendet.