scalatutorial.de

Stufe 2Sprachkern · Lektion 8 von 34

Funktionen und Methoden

Aktualisiert am 24. September 20263 Min. LesezeitSchritt 3/7 dieser Stufe

Methoden definieren Sie mit def, Funktionen sind Werte, die man herumreichen kann – und Operatoren wie + sind in Scala einfach Methoden mit ungewöhnlichem Namen. Diese Lektion zeigt, wie das zusammenpasst.

Methoden mit def

 Scala 3
def flaeche(breite: Double, hoehe: Double): Double =
  breite * hoehe

flaeche(3, 4.5)   // 13.5

Jeder Parameter braucht einen Typ, der Rückgabetyp ist optional, aber bei öffentlichen Methoden empfohlen. Der Rumpf ist ein Ausdruck, dessen Wert zurückgegeben wird – ein return ist nicht nötig.

Standardwerte und benannte Argumente

 Scala 3
def gruss(name: String, anrede: String = "Hallo", ausrufe: Int = 1): String =
  s"$anrede, $name" + "!" * ausrufe

gruss("Ada")                         // Hallo, Ada!
gruss("Ada", ausrufe = 3)            // Hallo, Ada!!!
gruss(anrede = "Servus", name = "Alan")

Standardwerte ersparen viele überladene Varianten einer Methode. Benannte Argumente machen Aufrufe mit mehreren gleichartigen Parametern lesbarer: verschiebe(x = 10, y = -4) ist eindeutiger als verschiebe(10, -4).

Variable Argumentanzahl

 Scala 3
def summe(zahlen: Int*): Int = zahlen.sum

summe(1, 2, 3)           // 6
val liste = List(4, 5)
summe(liste*)            // 9 – Liste „auspacken“

Funktionen als Werte

Neben Methoden gibt es Funktionswerte. Sie haben einen Typ wie Int => Int („von Int nach Int“) und lassen sich in Variablen speichern:

 Scala 3
val verdoppeln: Int => Int = x => x * 2
val addieren = (a: Int, b: Int) => a + b

verdoppeln(21)     // 42
addieren(2, 3)     // 5

Der Ausdruck x => x * 2 heißt anonyme Funktion oder Lambda. Besonders nützlich sind sie als Argumente anderer Methoden:

 Scala 3
val zahlen = List(1, 2, 3, 4)
zahlen.map(x => x * 2)    // List(2, 4, 6, 8)
zahlen.map(_ * 2)         // dasselbe, kürzer
zahlen.filter(_ % 2 == 0) // List(2, 4)

Der Unterstrich steht für „den jeweiligen Parameter“. Er eignet sich für kurze Ausdrücke; sobald ein Parameter zweimal vorkommt, brauchen Sie wieder einen Namen.

Methoden lassen sich ebenfalls übergeben. Scala wandelt sie automatisch in Funktionswerte um:

 Scala 3
def istGerade(n: Int): Boolean = n % 2 == 0
zahlen.filter(istGerade)   // List(2, 4)

Funktionen, die Funktionen liefern

 Scala 3
def multiplikator(faktor: Int): Int => Int = x => x * faktor

val mal3 = multiplikator(3)
mal3(14)   // 42

Die zurückgegebene Funktion „merkt“ sich den Wert von faktor. So etwas nennt man Closure. Funktionen, die Funktionen annehmen oder liefern, heißen Funktionen höherer Ordnung – ein Grundbaustein der funktionalen Programmierung.

Mehrere Parameterlisten

Eine Methode kann mehrere Parameterlisten haben. Das nennt man Currying:

 Scala 3
def wiederhole(n: Int)(aktion: => Unit): Unit =
  for _ <- 1 to n do aktion

wiederhole(3) {
  println("Scala")
}

Der Parameter aktion: => Unit ist ein By-Name-Parameter: Der übergebene Block wird nicht vorab ausgewertet, sondern bei jedem Zugriff neu. Zusammen mit der zweiten Parameterliste entsteht so etwas, das aussieht wie eine eingebaute Kontrollstruktur. Auf diese Weise sind viele Bibliotheken in Scala gebaut.

Operatoren sind Methoden

In Scala gibt es keine eingebauten Operatoren im engeren Sinn. 1 + 2 ist der Aufruf der Methode + auf dem Objekt 1:

 Scala 3
1 + 2       // entspricht 1.+(2)
"abc" * 2   // entspricht "abc".*(2), ergibt "abcabc"

Eigene Klassen können genauso Operatoren definieren:

 Scala 3
case class Geld(cent: Long):
  def +(anderes: Geld): Geld = Geld(cent + anderes.cent)
  override def toString = f"${cent / 100.0}%.2f €"

Geld(1999) + Geld(501)   // 25,00 € bzw. 25.00 € je nach Spracheinstellung

Umgekehrt lassen sich Methoden mit einem Parameter wie Operatoren aufrufen: a max b statt a.max(b). Scala 3 sieht dafür bei eigenen Methoden die Markierung infix vor (infix def plus(…)), sonst warnt der Compiler in strengeren Einstellungen. Für die meisten Methoden ist die Punktschreibweise ohnehin die lesbarere Wahl.

Extension Methods

Mit extension fügen Sie bestehenden Typen neue Methoden hinzu, ohne sie zu verändern:

 Scala 3
extension (s: String)
  def istPalindrom: Boolean =
    val t = s.toLowerCase.filter(_.isLetter)
    t == t.reverse

"Reliefpfeiler".istPalindrom   // true

Mehr über diesen Mechanismus und seine Scala-2-Vorgänger steht in der Lektion über given, using und implizite Konvertierung.

Passt dazu