Lassen Sie sich während einer beliebigen Scala-Code-Position in den Interpreter fallen

84

Ich komme aus einem Python-Hintergrund, den ich an jeder Stelle in meinem Code hinzufügen kann

import pdb; pdb.set_trace()

und zur Laufzeit werde ich an dieser Stelle in einen interaktiven Dolmetscher versetzt. Gibt es ein Äquivalent für Scala oder ist dies zur Laufzeit nicht möglich?

Lars Yencken
quelle
7
Im Sinne der "Wahrheit in der Werbung" hat Scala keinen Dolmetscher. Seine REPL ist "Compile-and-Go". Der REPL-Code (einschließlich des Compilers) kann jedoch auf Wunsch in Ihre Anwendung aufgenommen werden (siehe Abbildung unten)
Randall Schulz,
1
Die REPL wird jedoch ohne Kenntnis Ihres laufenden Kontexts gestartet, mit Ausnahme dessen, was Sie explizit und mühsam in Ihren REPL-Startcode einbinden. Siehe unten. Ich denke, in Python landest du im laufenden Kontext, der viel besser ist. Auf jeden Fall ist stackoverflow.com/questions/24674288/… aktueller.
Matanster

Antworten:

78

Ja, Sie können auf Scala 2.8. Beachten Sie, dass Sie die Datei scala-compiler.jar in Ihren Klassenpfad aufnehmen müssen, damit dies funktioniert. Wenn Sie Ihr Scala-Programm mit aufrufen scala, wird dies automatisch durchgeführt (so scheint es in den von mir durchgeführten Tests).

Sie können es dann folgendermaßen verwenden:

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)
    }
  }
}

Sie können mehrere DebugParamArgumente übergeben. Wenn die REPL angezeigt wird, wird der Wert rechts an einen Wert gebunden, dessen Namen Sie links angegeben haben. Wenn ich zum Beispiel diese Zeile wie folgt ändere:

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

Dann erfolgt die Ausführung folgendermaßen:

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

scala> j
res0: Int = 5

Sie setzen die Ausführung durch Eingabe fort :quit.

Sie können auch in REPL fallen bedingungslos durch den Aufruf break, das ein empfängt Listvon DebugParamanstelle eines Vararg. Hier ist ein vollständiges Beispiel, Code und Ausführung:

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)
    }
  }
}

Und dann:

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>
Daniel C. Sobral
quelle
3
Dies kann zu einem Fehler scala.tools.nsc.MissingRequirementError: object scala not found.in Scala 2.8 führen. Sie müssen explizit kann auf die Einstellungen von Scalac die Classpath des Host - Prozess zu übergeben, aber breakund breakIftun dies nicht. Hier ist eine gepatchte Version davon break: gist.github.com/290632
retronym
@retronym Lustig, es hat gerade hier funktioniert. Schicken Sie es an Paulp. Er erwähnte, dass dieses Ding sowieso geändert werden würde.
Daniel C. Sobral
Ich habe es mit einem JUnit-Test versucht, der von IntelliJ ausgeführt wurde. IntelliJ startete den Prozess mit java -classpath .... Ich denke, wenn Sie scala -classpathstattdessen verwenden, würde es gut funktionieren.
Retronym
4
Es war eine Abhängigkeit des Moduls und damit des Klassenpfads. 2.8 übergibt den Inhalt des java -classpathHost-Prozesses nicht an die Einstellungen für scalac: old.nabble.com/…
retronym
1
@ Huur Siehe Antwort von Răzvan Panda .
Daniel C. Sobral
24

Um Daniels Antwort ab Scala 2.9 zu ergänzen, sind die Methoden breakund breakIfin enthalten scala.tools.nsc.interpreter.ILoop. Auch DebugParamist jetzt NamedParam.

Kipton Barros
quelle
Sie müssen jline als Abhängigkeit hinzufügen .
schmmd
8
Kannst du bitte ein Beispiel mit der neuen Verwendung schreiben?
Will
24

IntelliJ IDEA:

  1. Führen Sie den Debug-Modus aus oder schließen Sie einen Remote-Debugger an
  2. Setzen Sie einen Haltepunkt und führen Sie ihn aus, bis Sie ihn erreichen
  3. Öffnen Sie das Fenster Evaluate Expression( Alt+ F8im Menü: Ausführen -> Ausdruck auswerten), um beliebigen Scala-Code auszuführen.
  4. Geben Sie das Codefragment oder den Ausdruck ein, den Sie ausführen möchten, und klicken Sie auf Auswerten
  5. Geben Sie Alt+ ein Voder klicken Sie auf Auswerten, um das Codefragment auszuführen.

Finsternis:

Ab Scala 2.10 wurden beide breakund breakIfaus entfernt ILoop.

Um in den Dolmetscher einzusteigen, müssen Sie mit arbeiten ILoop direkt mit ihm arbeiten.

Fügen Sie zuerst die scala compilerBibliothek hinzu. Klicken Sie für Eclipse Scala mit der rechten Maustaste auf project => Build Path=> Add Libraries...=> Scala Compiler.

Und dann können Sie Folgendes verwenden, um den Interpreter zu starten:

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()

In Eclipse Scala kann der Interpreter aus der ConsoleAnsicht verwendet werden:

Răzvan Flavius ​​Panda
quelle
18
Das ist schrecklich. :(
Daniel C. Sobral
@ Daniel Warum ist das schrecklich?
Hakkar
14
Weil es eine Menge Kesselplatten hinzufügt, die völlig unabhängig vom Ziel des Debuggens an einem Punkt im Programm sind und stattdessen mit der Mechanik zusammenhängen, die REPL in Gang zu bringen.
Daniel C. Sobral
1
@ Daniel gibt es einen besseren Weg in Scala 2.10?
Roterl
@roterl Was ist das Problem mit dem oben genannten?
Daniel C. Sobral