Respuestas:
De la publicación del blog " Llamadas de cola, @tailrec y trampolines ":
- En Scala 2.8, también podrá utilizar la nueva
@tailrec
anotación para obtener información sobre qué métodos están optimizados.
Esta anotación le permite marcar métodos específicos que espera que el compilador optimice.
A continuación, recibirá una advertencia si el compilador no los optimiza.- En Scala 2.7 o versiones anteriores, deberá confiar en las pruebas manuales o en la inspección del código de bytes para determinar si un método se ha optimizado.
Ejemplo:
puede agregar una
@tailrec
anotación para estar seguro de que los cambios han funcionado.
import scala.annotation.tailrec
class Factorial2 {
def factorial(n: Int): Int = {
@tailrec def factorialAcc(acc: Int, n: Int): Int = {
if (n <= 1) acc
else factorialAcc(n * acc, n - 1)
}
factorialAcc(1, n)
}
}
Y funciona desde el REPL (ejemplo de los consejos y trucos de Scala REPL ):
C:\Prog\Scala\tests>scala
Welcome to Scala version 2.8.0.RC5 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_18).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.annotation.tailrec
import scala.annotation.tailrec
scala> class Tails {
| @tailrec def boom(x: Int): Int = {
| if (x == 0) throw new Exception("boom!")
| else boom(x-1)+ 1
| }
| @tailrec def bang(x: Int): Int = {
| if (x == 0) throw new Exception("bang!")
| else bang(x-1)
| }
| }
<console>:9: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
@tailrec def boom(x: Int): Int = {
^
<console>:13: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden
@tailrec def bang(x: Int): Int = {
^
El compilador de Scala optimizará automáticamente cualquier método recursivo de cola. Si anotas un método que crees que es recursivo por cola con la @tailrec
anotación, el compilador te advertirá si el método en realidad no es recursivo por cola. Esto hace que la @tailrec
anotación sea una buena idea, tanto para garantizar que un método sea optimizable actualmente como para que siga siendo optimizable a medida que se modifica.
Tenga en cuenta que Scala no considera que un método sea recursivo en cola si se puede anular. Por lo tanto, el método debe ser privado, final, en un objeto (a diferencia de una clase o rasgo), o dentro de otro método a optimizar.
La anotación es scala.annotation.tailrec
. Desencadena un error del compilador si el método no se puede optimizar para la llamada final, lo que sucede si:
Se coloca justo antes de def
en una definición de método. Funciona en REPL.
Aquí importamos la anotación e intentamos marcar un método como @tailrec
.
scala> import annotation.tailrec
import annotation.tailrec
scala> @tailrec def length(as: List[_]): Int = as match {
| case Nil => 0
| case head :: tail => 1 + length(tail)
| }
<console>:7: error: could not optimize @tailrec annotated method: it contains a recursive call not in tail position
@tailrec def length(as: List[_]): Int = as match {
^
¡Ups! ¡La última invocación es 1.+()
, no length()
! Reformulemos el método:
scala> def length(as: List[_]): Int = {
| @tailrec def length0(as: List[_], tally: Int = 0): Int = as match {
| case Nil => tally
| case head :: tail => length0(tail, tally + 1)
| }
| length0(as)
| }
length: (as: List[_])Int
Tenga en cuenta que length0
es automáticamente privado porque está definido en el alcance de otro método.
override
anotación en Java: el código funciona sin él, pero si lo pones allí te dice si cometiste un error.