在任意 Scala 代码位置进入解释器

88

我来自Python的背景,在我的代码中任何时刻都可以添加

import pdb; pdb.set_trace()

我希望在运行时能够进入一个交互式解释器来执行代码。对于Scala是否有类似的功能,在运行时是否可能实现?


7
为了实现“广告真实性”,Scala没有解释器。它的REPL是“编译并运行”的。话虽如此,如果需要的话(如下所示),REPL代码(包括编译器)可以被整合到您的应用程序中。 - Randall Schulz
1
但是REPL将在没有任何关于您运行上下文的知识的情况下启动,除了您在REPL启动代码中明确而费力地绑定的内容。请参见下面。我认为在Python中,您会进入运行上下文,这要好得多。无论如何,https://dev59.com/XWAf5IYBdhLWcg3wbCJ3?lq=1更加更新。 - matanster
3个回答

79

是的,您可以在Scala 2.8上使用它。请注意,为了使其工作,您必须在类路径中包含scala-compiler.jar。如果您使用 scala 命令调用 Scala 程序,则会自动完成此操作(至少在我进行的测试中是如此)。

然后,您可以像这样使用它:

import scala.tools.nsc.Interpreter._

object TestDebugger {
  def main(args: Array[String]) {
    0 to 10 foreach { i =>
      breakIf(i == 5, DebugParam("i", i))
      println(i)
    }
  }
}

您可以传递多个DebugParam参数。当REPL出现时,右侧的值将绑定到一个由左侧提供的名称的val中。例如,如果我像这样更改该行:

      breakIf(i == 5, DebugParam("j", i))

然后执行将会按照以下方式进行:

C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int

scala> j
res0: Int = 5

输入 :quit 结束程序的执行。

你也可以通过调用 break 来无条件地进入 REPL,该方法接受一个 List 类型的 DebugParam 参数列表。以下是完整示例代码和执行结果:

import scala.tools.nsc.Interpreter._

object TestDebugger {
  def main(args: Array[String]) {
    0 to 10 foreach { i =>
      breakIf(i == 5, DebugParam("j", i))
      println(i)
      if (i == 7) break(Nil)
    }
  }
}

接着:

C:\Users\Daniel\Documents\Scala\Programas>scalac TestDebugger.scala

C:\Users\Daniel\Documents\Scala\Programas>scala TestDebugger
0
1
2
3
4
j: Int

scala> j
res0: Int = 5

scala> :quit
5
6
7

scala> j
<console>:5: error: not found: value j
       j
       ^

scala> :quit
8
9
10

C:\Users\Daniel\Documents\Scala\Programas>

3
在Scala 2.8中,这可能会导致一个错误 scala.tools.nsc.MissingRequirementError: object scala not found. 你可能需要显式地将主进程的类路径传递给Scalac的设置,但breakbreakIf 不会这样做。这是一个已修复的break版本,可以实现此功能:http://gist.github.com/290632 - retronym
4
这是该模块的一个依赖项,因此在类路径中。2.8不会将主进程的java -classpath内容传递给scalac的设置:http://old.nabble.com/-scala--recent-changes-in-2.8-nightly-classpath-management-td26233977.html - retronym
Scala 2.10及以上版本怎么办(添加了scala.reflect.universe._)? - Hakkar
1
请查看Răzvan Panda答案 - Daniel C. Sobral
谢谢丹尼尔!很抱歉没有注意到。我今晚稍后会检查一下。 - Hakkar
显示剩余10条评论

25

IntelliJ IDEA:

  1. 在 debug 模式下运行或连接远程调试器
  2. 设置断点并运行到达该断点
  3. 打开 Evaluate Expression 窗口(Alt+F8,在菜单中找到:Run -> Evaluate Expression),以运行任意的 Scala 代码。
  4. 输入您想要运行的代码片段或表达式,然后点击 Evaluate
  5. 键入 Alt+V 或点击 Evaluate 以运行代码片段。

Eclipse:

从 Scala 2.10 开始,ILoop 中的 breakbreakIf 已被删除。

要进入解释器,您将需要直接使用 ILoop

首先添加 scala 编译器 库。对于 Eclipse Scala,右键单击项目 => Build Path => Add Libraries... => Scala Compiler

接下来,您可以在以下位置使用以下代码启动解释器:

import scala.tools.nsc.interpreter.ILoop
import scala.tools.nsc.interpreter.SimpleReader
import scala.tools.nsc.Settings

val repl = new ILoop
repl.settings = new Settings
repl.settings.Yreplsync.value = true
repl.in = SimpleReader()
repl.createInterpreter()

// bind any local variables that you want to have access to
repl.intp.bind("row", "Int", row)
repl.intp.bind("col", "Int", col)

// start the interpreter and then close it after you :quit
repl.loop()
repl.closeInterpreter()

在Eclipse Scala中,解释器可以从“控制台(Console)”视图中使用:


@Daniel 为什么那很糟糕? - Hakkar
14
因为它增加了很多与在程序中调试目标完全无关的样板代码,相反地,这些代码与启动 REPL 的机制相关。 - Daniel C. Sobral
1
@Daniel,在Scala 2.10中有更好的方法吗? - roterl
@DanielC.Sobral 我更新了答案,使其更少糟糕(至少对于IntelliJ IDEA而言):) - Răzvan Flavius Panda
这可以用于创建一个REPL调试器,就像Pry一样,可以包含在Scala项目中。我有一种感觉,明确的“break”功能被删除是因为Scala语言的核心贡献者认为,拥有一种内置的方式来进入REPL以调试Scala不够灵活,并且会阻碍更好的调试工具的创新(而且这也是设计语言本身的范围扩展)。 - josiah
显示剩余4条评论

25

补充一下Daniel的回答,从Scala 2.9版本开始,breakbreakIf方法包含在scala.tools.nsc.interpreter.ILoop中。此外,DebugParam现在是NamedParam


你需要将 jline 添加为依赖项。 - schmmd
8
请你能否写一个新用法的例子? - Will

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接