【问题标题】:How to reload a class or package in Scala REPL?如何在 Scala REPL 中重新加载类或包?
【发布时间】:2011-01-29 03:22:18
【问题描述】:

我几乎总是打开一个或两个 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;

【问题讨论】:

  • 我猜这是工作表相对于 REPL 的好处之一

标签: scala read-eval-print-loop


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    :replay
    

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

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

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

    【讨论】:

    • 显然不适合密集课程,但我喜欢这个。这也意味着您将知道您的更改是否破坏了任何内容,测试/TDD 是否是您的目标。
    • 我认为这是错误的。 :replay重新加载类。
    • 我同意@AdamMackler,至少它似乎没有重新加载 2.10.4。
    • @mitchus - 我刚刚验证了 2.11.6 的重新加载行为。但是,它在 SBT 内部对我不起作用,至少不是以任何直接的方式。 2.10.4我没有具体检查过。
    • @RexKerr 是的,我的观察也是 w.r.t. “sbt 控制台”
    【解决方案3】:

    这对我有用....

    如果您的新源文件 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
    

    【讨论】:

    • 只有在Test.scala 的顶部没有定义package 时,这才适用于我。有任何想法吗?谢谢
    • 不知道。可能是错误的包路径
    【解决方案4】:

    有一个命令满足你的要求

    :load path/to/file.scala
    

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

    【讨论】:

    • 如果file.scala 在顶部定义了package,这对您有用吗?谢谢
    【解决方案5】:

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

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

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

    【讨论】:

    • 如何在调试模式下启动 scala repl?我正在使用 sbt 并运行“控制台”来为我的项目启动 scala repl,但不确定如何在调试模式下完成。
    猜你喜欢
    • 2013-11-22
    • 2011-12-01
    • 2012-07-03
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-17
    • 2018-06-01
    • 2021-05-21
    相关资源
    最近更新 更多