tailrec アノテーション
最適化を保証します。
「tailrec アノテーション」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
What is Tail Recursion?
A recursive call is in tail position when it is the very last action of the function. A tail-recursive function can be optimized into a loop, reusing a single stack frame, so it never overflows.
Tail Position
In n * factorial(n-1), the recursive call is not last: the multiplication happens after it returns. In gcd(b, a % b), the call is last. Only the latter is tail-recursive.
The @tailrec Annotation
Import scala.annotation.tailrec and annotate a method. The compiler then verifies the call is truly in tail position and applies the optimization. If it is not, compilation fails.
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)
}Guaranteed Optimization
The key benefit of @tailrec is the compile-time guarantee. You are told immediately if your function is not stack-safe, rather than discovering it via a runtime crash on large input.
A Tail-Recursive gcd
Euclid's algorithm is already tail-recursive: the recursive call is the entire body's result. Annotating it confirms this.
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))
}
}What Breaks Tail Position
Common patterns that move the call out of tail position:
- Doing arithmetic on the result:
n + f(...). - Wrapping in a constructor:
x :: f(...). - Using the result in a
tryblock.
Non-Tail Example
This sum is not tail-recursive because the addition wraps the call. Annotating it with @tailrec would cause a compile error. (Shown without the annotation so it runs.)
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))
}
}Why It Cannot Be Optimized
Because n + sum(n - 1) must remember n to finish the addition after the call returns, each level needs its own stack frame. The compiler cannot collapse this into a loop, so it is not tail-recursive.
A Large Tail-Recursive Loop
A tail-recursive sum using an accumulator runs for huge inputs without overflowing, because it reuses one frame.
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 Requires final or Local
For @tailrec to apply, the method must not be overridable: it must be private, final, or a local/nested method. An open method could be overridden, breaking the optimization, so the compiler rejects it.
Mutual Recursion Caveat
@tailrec only optimizes a function calling itself. Two functions calling each other (mutual recursion) cannot be tail-optimized by the JVM directly; for that you need trampolining, covered later.
Quick Check
Test your understanding of @tailrec.
Recap
You learned the @tailrec annotation:
- A call in tail position can be optimized into a loop.
@tailrecgives a compile-time guarantee of stack safety.- The method must be
final,private, or local. - It only covers self-recursion, not mutual recursion.
よくある質問
「tailrec アノテーション」レッスンは無料ですか?
はい。「tailrec アノテーション」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
「tailrec アノテーション」で何を学びますか?
最適化を保証します。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「tailrec アノテーション」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?
はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- 再帰の基礎
- tailrec アノテーション
- アキュムレーターパターン
- トランポリン