如何在Scala REPL中重新加载类或包?

Rex*_*err 44 scala read-eval-print-loop

我几乎总是有一个或两个Scala REPL会话,这使得Java或Scala类很容易进行快速测试.但是,如果我更改一个类并重新编译它,REPL将继续加载旧的类.有没有办法让它重新加载类,而不是必须重新启动REPL?

举一个具体的例子,假设我们有Test.scala文件:

object Test { def hello = "Hello World" }
Run Code Online (Sandbox Code Playgroud)

我们编译它并启动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
Run Code Online (Sandbox Code Playgroud)

然后我们将源文件更改为

object Test {
  def hello = "Hello World"
  def goodbye = "Goodbye, Cruel World"
}
Run Code Online (Sandbox Code Playgroud)

但是我们不能用它:

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;
Run Code Online (Sandbox Code Playgroud)

Rex*_*err 40

如果目标是不必重复先前的命令,则可以选择重新加载类.REPL有命令

:replay
Run Code Online (Sandbox Code Playgroud)

它会重新启动REPL环境并播放所有以前的有效命令.(跳过无效的,所以如果以前错了,它就不会突然工作.)当重置REPL时,它会重新加载类,所以新命令可以使用重新编译的类的内容(事实上,旧的命令也将使用那些重新编译的类).

这不是一般解决方案,但是用于扩展具有可重新计算状态的单个会话的有用快捷方式.

注意:这适用于裸Scala REPL.如果你从SBT或其他环境运行它,它可能会或可能不会工作,这取决于SBT或其他环境如何打包类 - 如果你不更新正在使用的实际类路径上的内容,当然它赢了'工作!

  • 我认为这是错误的.`:replay`确实*不*重新加载类. (5认同)

Dan*_*wak 28

类重新加载不是一个简单的问题.事实上,这是JVM非常困难的事情.你确实有几个选择:

  • 在调试模式下启动Scala REPL.JVM调试器有一些内置的重新加载,可以在方法级别上运行.它对你提供的案例没有帮助,但它会处理一些简单的事情,比如更改方法实现.
  • 使用JRebel(http://www.zeroturnaround.com/jrebel).JRebel基本上是JVM的超级类重载加载解决方案.它可以处理成员添加/删除,新/删除的类,定义更改等.它唯一无法处理的是类层次结构的更改(例如,添加超级接口).它不是一个免费工具,但它们提供的补充许可仅限于Scala编译单元.

不幸的是,这些都受到Scala REPL实施细节的限制.我使用JRebel,它通常可以解决问题,但仍然存在REPL不会反映重新加载的类的情况.不过,它总比没有好.

  • 如何在调试模式下启动scala repl?我正在使用sbt并运行'console'来为我的项目启动scala repl,但不确定如何在调试模式下完成. (10认同)

小智 8

有一个命令符合您的要求

:load path/to/file.scala
Run Code Online (Sandbox Code Playgroud)

这将重新加载scala源文件并重新编译到类,然后您可以重播代码


cev*_*ris 6

这对我有用....

如果您的新源文件Test.scala看起来像这样......

package com.tests

object Test {
  def hello = "Hello World"
  def goodbye = "Goodbye, Cruel World"
}
Run Code Online (Sandbox Code Playgroud)

首先必须将新更改加载到Scala控制台(REPL).

:load src/main/scala/com/tests/examples/Test.scala
Run Code Online (Sandbox Code Playgroud)

然后重新导入包,以便您可以在Scala控制台中引用新代码.

import com.tests.Test
Run Code Online (Sandbox Code Playgroud)

现在享受您的新代码,而无需重新启动您的会话:)

scala> Test.goodbye
res0: String = Goodbye, Cruel World
Run Code Online (Sandbox Code Playgroud)