2011-01-15 12 views
8

Definición de un método recursivo en un objeto:método es recursivo de cola cuando se define el objeto, pero no en la clase

object Recursive { 
    def recurse(maxDepth: Int = 10): Unit = { 
     if (maxDepth == 0) throw new Exception 
     recurse(maxDepth - 1) 
    } 
} 

da:

scala> Recursive.recurse(10) 
java.lang.Exception 
     at Recursive$.recurse(<console>:7) 
     at .<init>(<console>:7) 
     at .<clinit>(<console>) 
     at RequestResult$.<init>(<console>:9) 
     at RequestResult$.<clinit>(<console>) 
     at RequestResult$scala_repl_result(<console>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) 
     at java.lang.reflect.Method.invoke(Method.java:597) 
     at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
     at scala.tools.nsc.Interpreter$Request$$anonfun$loadAndRun$1$$anonfun$apply$17.apply(Interpreter.scala:988) 
     at scala.util.control.Exception$Catch.apply(Exception.scal... 

Pero definir en una clase:

class Recursive { 
    def recurse(maxDepth: Int = 10): Unit = { 
     if (maxDepth == 0) throw new Exception 
     recurse(maxDepth - 1) 
    } 
} 

gives:

scala> new Recursive recurse(10) 
java.lang.Exception 
     at Recursive.recurse(<console>:7) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at Recursive.recurse(<console>:8) 
     at .<init>(<console>:7) 
     at .<clinit>(<console>) 
     at RequestResult$.<init>(<console>:9) 
     at RequestResult$.<clinit>(<console>) 
     at RequestResult$scala_repl_result(<console>) 
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
     at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) 
     at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcc.. 

Los métodos son idénticos. ¿Por qué no es recursivo la cola cuando se define en una clase?

+1

siempre use @tailrec para verificar su intención – ron

Respuesta

16

Si desea que se realice la recursividad de cola, recurse no se puede sobrescribir. Si recurse es reemplazable, como en su declaración class, cualquier recursividad dentro de ella tiene que usar la invocación dinámica del método (porque es potencialmente polimórfica), que no se puede optimizar a una declaración de estilo de goto.

La declaración de singleton object garantiza estáticamente la llamada no ambigua a recurse, y permite que el compilador continúe con la optimización de recursividad de cola.

+0

¡Ah! Entonces "final recurse definitivamente ..." hace el truco. –

10

Si espera que un método sea recursivo de cola, debe anotarlo con @tailrec. Si el compilador no puede aplicar TCO, se producirá un error.

scala> import annotation._       
import annotation._ 

scala> class Recursive {          
    |  @tailrec def recurse(maxDepth: Int = 10): Unit = { 
    |   if (maxDepth == 0) throw new Exception   
    |   recurse(maxDepth - 1)       
    |  }             
    | } 
<console>:12: error: could not optimize @tailrec annotated method: it is neither private nor final so can be overridden 
      @tailrec def recurse(maxDepth: Int = 10): Unit = { 
         ^
Cuestiones relacionadas