Considérons la suite de l'interaction avec le REPL. Nous avons d'abord définir une classe avec une méthode factorielle:
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
Maintenant, nous allons le remplacer dans une sous-classe pour le double de la super-classe de la réponse:
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)
Quels résultats attendez-vous de ce dernier appel? Vous pourriez attendre de 240. Mais non:
scala> (new C2).fact(5, 1)
res13: Int = 7680
C'est parce que lors de la super-classe de la méthode fait appel récursif, l'appel récursif passe par la sous-classe.
Si une substitution travaillé tels que 240 était la bonne réponse, alors il serait sans danger pour la queue-appel d'optimisation pour être exécutée dans la super-classe ici. Mais ce n'est pas comment Scala (ou Java) fonctionne.
À moins qu'une méthode est marqué en finale, il pourrait ne pas être l'appel de lui-même quand il fait un appel récursif.
Et c'est pourquoi @tailrec ne fonctionne pas sauf si une méthode est définitive (ou privé).
Mise à JOUR: je vous recommande de lire les deux autres réponses (Jean et de Rex) ainsi.