2010-03-18 13 views
39

Casi siempre tengo una sesión de Scala REPL o dos abiertas, lo que hace que sea muy fácil dar una prueba rápida a las clases de Java o Scala. Pero si cambio una clase y la vuelvo a compilar, la REPL continúa con la anterior cargada. ¿Hay alguna manera de hacer que vuelva a cargar la clase, en lugar de tener que reiniciar el REPL?¿Cómo volver a cargar una clase o paquete en Scala REPL?

Sólo para dar un ejemplo concreto, supongamos que tenemos el archivo Test.scala:

object Test { def hello = "Hello World" } 

Compilamos y empezar el REPL:

~/pkg/scala-2.8.0.Beta1-prerelease$ bin/scala 
Welcome to Scala version 2.8.0.Beta1-prerelease 
(Java HotSpot(TM) Server VM, Java 1.6.0_16). 
Type in expressions to have them evaluated. 
Type :help for more information. 

scala> Test.hello 
res0: java.lang.String = Hello World 

Luego cambiamos el archivo de origen a

object Test { 
    def hello = "Hello World" 
    def goodbye = "Goodbye, Cruel World" 
} 

pero no podemos usarlo:

scala> Test.goodbye 
<console>:5: error: value goodbye is not a member of object Test 
     Test.goodbye 
      ^

scala> import Test; 
<console>:1: error: '.' expected but ';' found. 
     import Test; 
+0

Supongo que es un beneficio de las hojas de cálculo sobre REPL – nafg

Respuesta

26

La recarga de clase no es un problema fácil. De hecho, es algo que la JVM hace muy difícil. Sin embargo, tiene un par de opciones:

  • Inicie el Scala REPL en modo de depuración. El depurador JVM tiene una recarga incorporada que funciona en el nivel de método. No lo ayudará con el caso que dio, pero manejaría algo simple como cambiar la implementación de un método.
  • Utilice JRebel (http://www.zeroturnaround.com/jrebel). JRebel es básicamente una solución de recarga de clase súper cargada para la JVM . Puede manejar miembro adición/eliminación, clases nuevas/eliminadas, cambios de definición, etc. Casi lo único que no puede manejar son los cambios en la jerarquía de clases (agregando una super-interfaz, para el ejemplo ). No es una herramienta gratuita, pero ofrecen una licencia complementaria que se limita a las unidades de compilación de Scala.

Desafortunadamente, ambos están limitados por los detalles de implementación de Scala REPL. Yo uso JRebel, y generalmente funciona, pero todavía hay casos en que el REPL no reflejará la (s) clase (s) recargada (s). Aún así, es mejor que nada.

+7

¿Cómo se inicia scala repl en modo de depuración? Estoy usando sbt y ejecutando 'console' para iniciar Scala repl para mi proyecto, pero no estoy seguro de cómo se podría hacer en modo de depuración. – mmrobins

36

Existe una alternativa para volver a cargar la clase si el objetivo es no tener que repetir los comandos anteriores. El REPL tiene el comando

:replay 

que reinicia el entorno REPL y reproduce todos los comandos válidos anteriores. (Los inválidos se omiten, por lo que si antes era incorrecto, no funcionarán de repente). Cuando se restablece el REPL, vuelve a cargar clases, por lo que los nuevos comandos pueden usar los contenidos de las clases recompiladas (de hecho, los comandos anteriores) también usará esas clases recompiladas).

Esta no es una solución general, pero es un atajo útil para extender una sesión individual con un estado recalculable.

Nota: esto se aplica a Scala REPL. Si lo ejecuta desde SBT o algún otro entorno, puede funcionar o no dependiendo de cómo SBT o el otro entorno empaca las clases; si no actualiza lo que está en la ruta de clase real que se está utilizando, por supuesto que ganó ' t trabajo!

+0

Obviamente mal para sesiones intensivas, pero me gusta esto. También significa que sabrá si sus cambios rompieron cualquier cosa, si probar/TDD es su objetivo. – Grogs

+4

Creo que esto está mal. ': replay' does * not * reload classes. –

+0

Estoy de acuerdo con @AdamMackler, al menos no parece volver a cargar con 2.10.4. – mitchus

5

hay un comando de cumplir con el requisito

:load path/to/file.scala 

que se vuelva a cargar el archivo de origen Scala y volver a compilar las clases, entonces usted puede reproducir código que

+1

¿Esto funciona para usted si 'file.scala' tiene un' paquete' definido en la parte superior? Gracias –

5

Esto funciona para mí ....

Si el nuevo archivo de origen Test.scala ve algo como esto ...

package com.tests 

object Test { 
    def hello = "Hello World" 
    def goodbye = "Goodbye, Cruel World" 
} 

Primero tiene que cargar los nuevos cambios en la consola de Scala (REPL).

:load src/main/scala/com/tests/examples/Test.scala 

A continuación, vuelva a importar el paquete para que pueda consultar el nuevo código en la consola de Scala.

import com.tests.Test 

Ahora disfrutar de su nuevo código sin necesidad de reiniciar la sesión :)

scala> Test.goodbye 
res0: String = Goodbye, Cruel World 
+0

Esto funciona solo si no se define 'paquete' en la parte superior de' Test.scala'. ¿Algunas ideas? Gracias –

+0

No lo sé. Tal vez mal camino del paquete – cevaris

0

Si el archivo .scala se encuentra en el directorio en el que se inicia el REPL puede ommit la ruta completa, sólo hay que poner :load myfile.scala, y luego importar

Cuestiones relacionadas