ส่งล่ามระหว่างตำแหน่งรหัสสกาล่าโดยพลการ


85

ฉันมาจากพื้นหลัง Python ซึ่งเมื่อใดก็ได้ในโค้ดของฉันฉันสามารถเพิ่มได้

import pdb; pdb.set_trace()

และเมื่อรันไทม์ฉันจะถูกส่งไปเป็นล่ามแบบโต้ตอบที่จุดนั้น มีสกาลาเทียบเท่าหรือไม่ในรันไทม์?


7
ด้วยจิตวิญญาณของ "ความจริงในการโฆษณา" สกาล่าไม่มีล่าม REPL คือ "compile-and-go" ที่กล่าวว่ารหัส REPL (รวมถึงคอมไพเลอร์) สามารถรวมเข้ากับแอปพลิเคชันของคุณได้หากต้องการ (ตามที่แสดงด้านล่าง)
Randall Schulz

1
แต่ REPL จะเปิดตัวโดยไม่มีความรู้เกี่ยวกับบริบทการทำงานของคุณยกเว้นสิ่งที่คุณผูกไว้อย่างชัดเจนและลำบากในรหัสการเริ่มใช้งาน REPL ของคุณ ดูด้านล่าง ฉันคิดว่าใน python คุณเข้าสู่บริบทการทำงานซึ่งดีกว่ามาก อย่างไรก็ตามstackoverflow.com/questions/24674288/…เป็นข้อมูลล่าสุด
matanster

คำตอบ:


78

ใช่คุณทำได้บน Scala 2.8 โปรดทราบว่าเพื่อให้ได้ผลคุณต้องรวม scala-compiler.jar ใน classpath ของคุณ หากคุณเรียกใช้โปรแกรมสกาล่าด้วยโปรแกรม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 ปรากฏขึ้นค่าทางด้านขวาจะถูกผูกไว้กับค่าที่คุณระบุไว้ทางด้านซ้าย ตัวอย่างเช่นถ้าฉันเปลี่ยนบรรทัดเป็นแบบนี้:

      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คุณยังคงดำเนินการโดยการพิมพ์

นอกจากนี้คุณยังสามารถลดลงใน REPL โดยไม่มีเงื่อนไขได้โดยการเรียกใช้breakซึ่งได้รับ a 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 คุณอาจต้องชัดเจนผ่าน classpath ของกระบวนการโฮสต์การตั้งค่าของ Scalac แต่breakและbreakIfไม่ทำเช่นนี้ นี่คือเวอร์ชันที่ได้รับการแก้ไขแล้วbreak: gist.github.com/290632
retronym

@retronym ตลกมันใช้งานได้ที่นี่ ส่งไปที่ paulp เขากล่าวว่าสิ่งนี้กำลังจะเปลี่ยนไป
Daniel C. Sobral

ฉันลองจากการทดสอบ JUnit ซึ่งดำเนินการโดย IntelliJ IntelliJ เปิดตัวกระบวนการด้วยjava -classpath .... ฉันเดาว่าถ้าคุณใช้scala -classpathแทนมันจะใช้ได้ดี
retronym

4
มันเป็นการพึ่งพาของโมดูลและด้วยเหตุนี้ในคลาสพา ธ 2.8 ไม่ผ่านเนื้อหาของjava -classpathกระบวนการโฮสต์ไปยังการตั้งค่าสำหรับ scalac: old.nabble.com/…
retronym

1
@Huur ดูคำตอบโดยRăzvanแพนด้า
Daniel C. Sobral

24

เพื่อเพิ่มคำตอบของ Daniel ณ Scala 2.9 breakและbreakIfวิธีการมีอยู่ในscala.tools.nsc.interpreter.ILoop. นอกจากนี้ยังมีอยู่ในขณะนี้DebugParamNamedParam


คุณจะต้องเพิ่มjlineเป็นการอ้างอิง
schmmd

8
คุณช่วยเขียนตัวอย่างการใช้งานใหม่ได้ไหม
Will

24

IntelliJ IDEA:

  1. ทำงานในโหมดดีบักหรือแนบตัวดีบักระยะไกล
  2. ตั้งเบรกพอยต์และเรียกใช้จนกว่าจะถึงจุดนั้น
  3. เปิดหน้าต่างEvaluate Expression( Alt+ F8ในเมนู: เรียกใช้ -> ประเมินนิพจน์) เพื่อเรียกใช้รหัสสกาล่าโดยพลการ
  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 ดำเนินต่อไป
Daniel C. Sobral

1
@ Daniel มีวิธีไหนที่ดีกว่านี้ใน scala 2.10?
roterl

@roterl ข้างต้นมีปัญหาอะไร
Daniel C. Sobral

@ คุณ
แดเนียล
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.