Passer dans l'interpréteur lors de l'emplacement arbitraire du code scala


84

Je viens d'un fond Python, où à tout moment dans mon code je peux ajouter

import pdb; pdb.set_trace()

et au moment de l'exécution, je serai déposé dans un interprète interactif à cet endroit. Existe-t-il un équivalent pour scala, ou n'est-ce pas possible au moment de l'exécution?


7
Dans l'esprit de «vérité dans la publicité», Scala n'a pas d'interprète. Son REPL est «compile-and-go». Cela dit, le code REPL (y compris le compilateur) peut être incorporé dans votre application, si vous le souhaitez (comme indiqué ci-dessous)
Randall Schulz

1
Mais le REPL se lancera sans aucune connaissance de votre contexte d'exécution, sauf pour ce que vous liez explicitement et laborieusement dans votre code de lancement de REPL. Voir ci-dessous. Je pense qu'en python vous atterrissez dans le contexte de fonctionnement, ce qui est bien meilleur. de toute façon, stackoverflow.com/questions/24674288/... est plus à jour.
matanster le

Réponses:


78

Oui, vous pouvez, sur Scala 2.8. Notez que, pour que cela fonctionne, vous devez inclure le scala-compiler.jar dans votre chemin de classe. Si vous invoquez votre programme scala avec scala, cela se fera automatiquement (du moins il semble dans les tests que j'ai effectués).

Vous pouvez ensuite l'utiliser comme ceci:

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

Vous pouvez passer plusieurs DebugParamarguments. Lorsque le REPL apparaît, la valeur à droite sera liée à un val dont vous avez fourni le nom à gauche. Par exemple, si je change cette ligne comme ceci:

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

Ensuite, l'exécution se déroulera comme ceci:

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

scala> j
res0: Int = 5

Vous continuez l'exécution en tapant :quit.

Vous pouvez également passer inconditionnellement dans REPL en invoquant break, qui reçoit un Listof DebugParamau lieu d'un vararg. Voici un exemple complet, code et exécution:

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

Puis:

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
Cela peut conduire à une erreur scala.tools.nsc.MissingRequirementError: object scala not found.dans Scala 2.8. Vous devrez peut - être passer explicitement le classpath du processus hôte aux paramètres de Scalac, mais breaket breakIfne pas le faire. Voici une version corrigée de breakcela: gist.github.com/290632
retronym

@retronym Drôle, ça a marché ici. Envoyez-le à paulp. Il a mentionné que cette chose allait être changée de toute façon.
Daniel C.Sobral

Je l'ai essayé à partir d'un test JUnit, exécuté par IntelliJ. IntelliJ a lancé le processus avec java -classpath .... Je suppose que si vous utilisez à la scala -classpathplace, cela fonctionnerait bien.
retronym

4
C'était une dépendance du module, et donc dans le classpath. 2.8 ne transmet pas le contenu du java -classpathprocessus hôte aux paramètres de scalac: old.nabble.com
...

1
@Huur Voir la réponse de Răzvan Panda .
Daniel C.Sobral

24

Pour ajouter à la réponse de Daniel, à partir de Scala 2.9, les méthodes breaket breakIfsont contenues dans scala.tools.nsc.interpreter.ILoop. Aussi, DebugParamest maintenant NamedParam.


Vous devrez ajouter jline en tant que dépendance.
schmmd

8
pouvez-vous s'il vous plaît écrire un exemple avec la nouvelle utilisation?
Volonté le

24

IntelliJ IDEA:

  1. Exécuter en mode débogage ou attacher un débogueur distant
  2. Définissez un point d'arrêt et exécutez jusqu'à ce que vous l'atteigniez
  3. Ouvrez la fenêtre Evaluate Expression( Alt+ F8, dans le menu: Exécuter -> Evaluer l'expression) pour exécuter du code Scala arbitraire.
  4. Tapez le fragment de code ou l'expression que vous souhaitez exécuter et cliquez sur Évaluer
  5. Tapez Alt+ Vou cliquez sur Evaluer pour exécuter le fragment de code.

Éclipse:

Depuis Scala 2.10, les deux breaket breakIfont été supprimés de ILoop.

Pour entrer par effraction, vous devrez travailler ILoopdirectement avec .

Ajoutez d'abord une scala compilerbibliothèque. Pour Eclipse Scala, faites un clic droit sur project => Build Path=> Add Libraries...=> Scala Compiler.

Et puis vous pouvez utiliser ce qui suit où vous souhaitez démarrer l'interpréteur:

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

Dans Eclipse Scala, l'interpréteur peut être utilisé depuis la Consolevue:


18
C'est horrible. :(
Daniel C. Sobral

@Daniel Pourquoi est-ce horrible?
Hakkar

14
Parce qu'il ajoute beaucoup de détails techniques qui n'ont aucun rapport avec l'objectif de débogage à un moment donné du programme, et, à la place, liés aux mécanismes de mise en route du REPL.
Daniel C.Sobral

1
@Daniel y a-t-il un meilleur moyen dans scala 2.10?
roterl

@roterl Quel est le problème avec ce qui précède?
Daniel C.Sobral
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.