REPLとの次の相互作用を検討してください。まず、階乗メソッドを使用してクラスを定義します。
scala> class C {
def fact(n: Int, result: Int): Int =
if(n == 0) result
else fact(n - 1, n * result)
}
defined class C
scala> (new C).fact(5, 1)
res11: Int = 120
次に、サブクラスでオーバーライドして、スーパークラスの答えを2倍にします。
scala> class C2 extends C {
override def fact(n: Int, result: Int): Int = 2 * super.fact(n, result)
}
defined class C2
scala> (new C).fact(5, 1)
res12: Int = 120
scala> (new C2).fact(5, 1)
この最後の電話でどのような結果を期待しますか?あなたは240を期待しているかもしれません。しかし、違います:
scala> (new C2).fact(5, 1)
res13: Int = 7680
これは、スーパークラスのメソッドが再帰呼び出しを行うときに、再帰呼び出しがサブクラスを通過するためです。
240が正解であるようにオーバーライドが機能した場合、ここのスーパークラスで末尾呼び出しの最適化を実行しても安全です。しかし、それはScala(またはJava)の仕組みではありません。
メソッドがfinalとマークされていない限り、再帰呼び出しを行うときにメソッド自体を呼び出さない可能性があります。
そのため、メソッドがfinal(またはプライベート)でない限り、@tailrecは機能しません。
更新:他の2つの回答(ジョンとレックス)も読むことをお勧めします。