Scala for Backend Engineering & Functional Programming · Lektion

Die tailrec-Annotation

Garantierte Optimierung

Lektion 2 von 413 Schritte

Die tailrec-Annotation ist eine kostenlose Scala for Backend Engineering & Functional Programming-Lektion auf CoddyKit. Dies ist Lektion 2 von 4. Du kannst die komplette Lektion unten kostenlos lesen – dann übst du sie direkt im Browser mit einem integrierten Code-Editor und einem KI-Tutor rund um die Uhr. Sie ist Teil des Scala for Backend Engineering & Functional Programming-Lernpfads, und dein Fortschritt wird über Web und CoddyKit-App synchronisiert. Der Scala for Backend Engineering & Functional Programming-Kurs umfasst insgesamt 4 Lektionen.

Was ist Endrekursion?

Ein rekursiver Aufruf befindet sich in Endposition, wenn er die allerletzte Aktion der Funktion ist. Eine endrekursive Funktion kann zu einer Schleife optimiert werden, die einen einzigen Stack-Frame wiederverwendet, sodass kein Überlauf auftritt.

Endposition

In n * factorial(n-1) ist der rekursive Aufruf nicht der letzte Schritt: Die Multiplikation findet statt, nachdem er zurückgekehrt ist. In gcd(b, a % b) ist der Aufruf der letzte Schritt. Nur der zweite Fall ist endrekursiv.

Die Annotation @tailrec

Importieren Sie scala.annotation.tailrec und annotieren Sie eine Methode. Der Compiler prüft dann, ob sich der Aufruf tatsächlich in Endposition befindet, und wendet die Optimierung an. Ist dies nicht der Fall, schlägt die Kompilierung fehl.

import scala.annotation.tailrec

object Main {
  @tailrec
  def countdown(n: Int): Unit = {
    if (n >= 0) {
      println(n)
      countdown(n - 1)
    }
  }

  def main(args: Array[String]): Unit = countdown(3)
}

Garantierte Optimierung

Der wichtigste Vorteil von @tailrec ist die Garantie zur Compile-Zeit. Sie erfahren sofort, wenn Ihre Funktion nicht stapelsicher ist, statt dies erst durch einen Laufzeitabsturz bei einer großen Eingabe festzustellen.

Eine endrekursive gcd

Der euklidische Algorithmus ist bereits endrekursiv: Der rekursive Aufruf ist das gesamte Ergebnis des Funktionskörpers. Durch die Annotation wird dies bestätigt.

import scala.annotation.tailrec

object Main {
  @tailrec
  def gcd(a: Int, b: Int): Int =
    if (b == 0) a else gcd(b, a % b)

  def main(args: Array[String]): Unit = {
    println(gcd(1071, 462))
  }
}

Was die Endposition aufhebt

Häufige Muster, die den Aufruf aus der Endposition verschieben:

  • Arithmetik mit dem Ergebnis: n + f(...).
  • Einpacken in einen Konstruktor: x :: f(...).
  • Verwendung des Ergebnisses in einem try-Block.

Beispiel ohne Endrekursion

Diese Summe ist nicht endrekursiv, weil die Addition den Aufruf umschließt. Eine Annotation mit @tailrec würde einen Kompilierungsfehler verursachen. (Sie wird ohne Annotation gezeigt, damit sie ausgeführt werden kann.)

object Main {
  def sum(n: Int): Int =
    if (n == 0) 0
    else n + sum(n - 1)

  def main(args: Array[String]): Unit = {
    println(sum(100))
  }
}

Warum dies nicht optimiert werden kann

Da n + sum(n - 1) den Wert n speichern muss, um die Addition nach der Rückkehr des Aufrufs abzuschließen, benötigt jede Ebene ihren eigenen Stack-Frame. Der Compiler kann dies nicht zu einer Schleife zusammenfassen, daher ist die Funktion nicht endrekursiv.

Eine große endrekursive Schleife

Eine endrekursive Summe mit einem Akkumulator kann für sehr große Eingaben ausgeführt werden, ohne einen Überlauf zu verursachen, da sie einen einzigen Frame wiederverwendet.

import scala.annotation.tailrec

object Main {
  @tailrec
  def sumTo(n: Int, acc: Long = 0): Long =
    if (n == 0) acc else sumTo(n - 1, acc + n)

  def main(args: Array[String]): Unit = {
    println(sumTo(1000000))
  }
}

tailrec erfordert final oder lokal

Damit @tailrec angewendet werden kann, darf die Methode nicht überschreibbar sein: Sie muss private, final oder eine lokale bzw. verschachtelte Methode sein. Eine offene Methode könnte überschrieben werden, wodurch die Optimierung ungültig würde; deshalb weist der Compiler sie zurück.

Besonderheit bei gegenseitiger Rekursion

@tailrec optimiert nur eine Funktion, die sich selbst aufruft. Zwei Funktionen, die sich gegenseitig aufrufen (gegenseitige Rekursion), können von der JVM nicht direkt endrekursiv optimiert werden; dafür benötigen Sie Trampolining, das später behandelt wird.

Kurztest

Testen Sie Ihr Verständnis von @tailrec.

Zusammenfassung

Sie haben die Annotation @tailrec kennengelernt:

  • Ein Aufruf in Endposition kann zu einer Schleife optimiert werden.
  • @tailrec garantiert zur Compile-Zeit die Stapelsicherheit.
  • Die Methode muss final, private oder lokal sein.
  • Die Annotation gilt nur für Selbstrekursion, nicht für gegenseitige Rekursion.
Kostenlos starten

Lerne Scala mit einem KI-Tutor — kostenlos

Schreibe und führe echten Code in deinem Browser aus, bekomme sofortige Hilfe von einem 24/7 KI-Tutor und setze dein Lernen im Web oder in der App fort.

Kurse
39
Lektionen
143

Häufig gestellte Fragen

Ist die Lektion „Die tailrec-Annotation“ kostenlos?

Ja — der vollständige Text von „Die tailrec-Annotation“ ist hier im Web kostenlos zu lesen. Um sie interaktiv zu üben (integrierter Code-Editor und 24/7 KI-Tutor) und den Rest des Scala for Backend Engineering & Functional Programming-Kurses freizuschalten, upgrade auf CoddyKit PRO. Der Scala for Backend Engineering & Functional Programming-Kurs umfasst insgesamt 4 Lektionen.

Was lerne ich in „Die tailrec-Annotation“?

Garantierte Optimierung Du übst Scala for Backend Engineering & Functional Programming mit praktischem Code, den du direkt im Browser ausführst, und ein 24/7 KI-Tutor beantwortet deine Fragen während du die Lektion bearbeitest.

Brauche ich Erfahrung, um Scala for Backend Engineering & Functional Programming zu starten?

Keine Vorkenntnisse erforderlich. Scala for Backend Engineering & Functional Programming auf CoddyKit ist für Anfänger bis fortgeschrittene Lernende strukturiert, sodass du hier starten oder von Anfang an beginnen und in deinem eigenen Tempo voranschreiten kannst. Dies ist Lektion 2 von 4.

Wie lange dauert die Lektion „Die tailrec-Annotation“?

Die meisten CoddyKit-Lektionen dauern etwa 5–10 Minuten. Jede ist kompakt und interaktiv, sodass du stetig Fortschritte machst und genau dort weitermachst, wo du aufgehört hast – im Web und in der App.

Kann ich in dieser Scala for Backend Engineering & Functional Programming-Lektion Code schreiben und ausführen?

Ja. Jede Scala for Backend Engineering & Functional Programming-Lektion enthält einen integrierten Code-Editor, sodass du echten Code direkt in deinem Browser schreibst und ausführst und sofort KI-Feedback erhältst — ohne lokale Einrichtung erforderlich.

Alle Lektionen in diesem Kurs

  1. Rekursionsgrundlagen
  2. Die tailrec-Annotation
  3. Akkumulator-Muster
  4. Trampolining
← Zurück zu Scala for Backend Engineering & Functional Programming