Перейти в интерпретатор при произвольном расположении кода Scala

85

Я пришел из Python, где в любой момент своего кода я могу добавить

import pdb; pdb.set_trace()

и во время выполнения я попаду в интерактивный интерпретатор в этом месте. Есть ли эквивалент для scala или это невозможно во время выполнения?

Ларс Йенкен
источник
7
В духе «истины в рекламе» у Scala нет интерпретатора. Его REPL является «компилируемым и работающим». Тем не менее, код REPL (включая компилятор) может быть включен в ваше приложение, если вы хотите (как показано ниже)
Рэндалл Шульц
1
Но REPL запустится без какого-либо знания вашего рабочего контекста, за исключением того, что вы явно и кропотливо связываете в своем коде запуска REPL. Смотри ниже. Я думаю, что в python вы попадаете в рабочий контекст, что намного лучше. в любом случае, stackoverflow.com/questions/24674288/… более актуален.
Matanster 06

Ответы:

78

Да, в 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, который получает Listиз DebugParamвместо vararg. Вот полный пример, код и исполнение:

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.tools.nsc.MissingRequirementError: object scala not found.в Scala 2.8. Возможно , вам потребуется явно передать путь к классам хост - процесса в Настройках Scalac, но breakи breakIfне делать этого. Вот исправленная версия , breakчто делает: gist.github.com/290632
ретроним
@retronym Забавно, здесь это сработало. Отправьте его в paulp. Он упомянул, что эту вещь все равно собираются изменить.
Дэниел С. Собрал,
Я попробовал это из теста JUnit, запущенного IntelliJ. IntelliJ запустил процесс с помощью java -classpath .... Я думаю, если вы используете scala -classpathвместо этого, он будет работать нормально.
ретроним
4
Это была зависимость модуля и, следовательно, пути к классам. 2,8 не проходит содержание java -classpathпроцесса пребывания в настройках для scalac: old.nabble.com/...
ретроним
1
@Huur См ответ на Răzvan Panda .
Дэниел С. Собрал
24

Для того, чтобы добавить к ответу Даниила, как и в Scala 2.9, то breakи breakIfметоды содержатся в scala.tools.nsc.interpreter.ILoop. Также DebugParamсейчас NamedParam.

Киптон Баррос
источник
Вам нужно будет добавить jline в качестве зависимости.
schmmd
8
не могли бы вы написать пример с новым использованием?
Will
24

IntelliJ IDEA:

  1. Запустить в режиме отладки или подключить удаленный отладчик
  2. Установите точку останова и бегите, пока не дойдете до нее
  3. Откройте Evaluate Expression( Alt+ F8, в меню: Run -> Evaluate Expression) окно для запуска произвольного кода Scala.
  4. Введите фрагмент кода или выражение, которое вы хотите запустить, и нажмите «Оценить».
  5. Введите Alt+ Vили щелкните по Evaluate, чтобы запустить фрагмент кода.

Затмение:

Начиная с Scala 2.10, оба breakи breakIfбыли удалены из ILoop.

Чтобы взломать интерпретатор, вам придется работать ILoopнапрямую.

Сначала добавьте scala compilerбиблиотеку. Для 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представления:

Рэзван Флавиус Панда
источник
@ Дэниел Почему это ужасно?
Hakkar
14
Потому что он добавляет много шаблонов, которые совершенно не связаны с целью отладки в какой-либо точке программы, а, вместо этого, связаны с механикой запуска REPL.
Дэниел С. Собрал
1
@ Дэниел есть ли способ лучше в scala 2.10?
roterl 08
@roterl В чем проблема?
Дэниел С. Собрал,
@Daniel, вы написали: «Это ужасно. :(» с объяснением почему. Я согласен с этим. Но есть ли способ лучше?
roterl