51

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

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

object Test { def hello = "Hello World" }

我们编译它并启动 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

然后我们把源文件改成

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

但我们不能使用它:

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;
4

5 回答 5

41

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

:replay

它将重新启动 REPL 环境并播放所有以前的有效命令。(无效的会被跳过,所以如果之前出错,它不会突然起作用。)当REPL重置时,它会重新加载类,因此新命令可以使用重新编译的类的内容(实际上是旧命令)还将使用那些重新编译的类)。

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

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

于 2010-03-18T23:06:41.510 回答
32

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

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

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

于 2010-03-18T18:57:24.367 回答
8

有一个命令满足你的要求

:load path/to/file.scala

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

于 2014-09-26T07:53:03.783 回答
7

这对我有用....

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

package com.tests

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

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

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

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

import com.tests.Test

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

scala> Test.goodbye
res0: String = Goodbye, Cruel World
于 2014-09-26T20:37:03.593 回答
2

如果 .scala 文件位于启动 REPL 的目录中,则可以省略完整路径,只需 put :load myfile.scala,然后导入。

于 2015-10-07T20:15:15.950 回答