Thả vào trình thông dịch trong vị trí mã scala tùy ý


84

Tôi đến từ nền tảng Python, nơi tôi có thể thêm vào bất kỳ điểm nào trong mã của mình

import pdb; pdb.set_trace()

và trong thời gian chạy, tôi sẽ được đưa vào một thông dịch viên tương tác tại điểm đó. Có tương đương cho scala không, hoặc điều này không thể thực hiện được trong thời gian chạy?


7
Với tinh thần “sự thật trong quảng cáo”, Scala không có phiên dịch. REPL của nó là "compile-and-go." Điều đó nói rằng, mã REPL (bao gồm trình biên dịch) có thể được tích hợp vào ứng dụng của bạn, nếu bạn muốn (như hình dưới đây)
Randall Schulz

1
Nhưng REPL sẽ khởi chạy mà không có bất kỳ kiến ​​thức nào về ngữ cảnh đang chạy của bạn ngoại trừ những gì bạn ràng buộc một cách rõ ràng và tốn công sức trong mã khởi chạy REPL của mình. Xem bên dưới. Tôi nghĩ rằng trong python bạn hạ cánh vào bối cảnh đang chạy sẽ tốt hơn nhiều. dù sao, stackoverflow.com/questions/24674288/… là cập nhật hơn.
matanster

Câu trả lời:


78

Có, bạn có thể, trên Scala 2.8. Lưu ý rằng, để điều này hoạt động, bạn phải bao gồm scala-compiler.jar trong classpath của mình. Nếu bạn gọi chương trình scala của mình bằng scala, nó sẽ được thực hiện tự động (hoặc có vẻ như trong các thử nghiệm tôi đã thực hiện).

Sau đó, bạn có thể sử dụng nó như thế này:

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

Bạn có thể chuyển nhiều DebugParamđối số. Khi REPL xuất hiện, giá trị ở bên phải sẽ được liên kết với một val có tên mà bạn đã cung cấp ở bên trái. Ví dụ: nếu tôi thay đổi dòng đó như thế này:

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

Sau đó, quá trình thực thi sẽ diễn ra như thế này:

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

scala> j
res0: Int = 5

Bạn tiếp tục thực hiện bằng cách gõ :quit.

Bạn cũng có thể vô điều kiện thả vào REPL bằng cách gọi break, mà nhận được một Listsố DebugParamthay vì một vararg. Đây là một ví dụ đầy đủ, mã và thực thi:

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

Và sau đó:

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
Điều này có thể dẫn đến lỗi scala.tools.nsc.MissingRequirementError: object scala not found.trong Scala 2.8. Bạn có thể cần phải vượt qua một cách rõ ràng classpath của quá trình máy chủ vào màn hình Settings của Scalac, nhưng breakbreakIfkhông làm điều này. Dưới đây là một phiên bản vá của breakđiều đó: gist.github.com/290632
retronym

@retronym Buồn cười, nó chỉ hoạt động ở đây. Gửi nó đến paulp. Anh ấy đã đề cập rằng điều này sẽ được thay đổi dù sao.
Daniel C. Sobral

Tôi đã thử nó từ một bài kiểm tra JUnit, do IntelliJ chạy. IntelliJ đã khởi chạy quy trình với java -classpath .... Tôi đoán nếu bạn sử dụng scala -classpaththay thế nó sẽ hoạt động tốt.
retronym

4
Đó là một phần phụ thuộc của mô-đun, và do đó trong classpath. 2.8 không vượt qua các nội dung của java -classpathquá trình máy chủ để các cài đặt cho scalac: old.nabble.com/...
retronym


24

Để thêm vào câu trả lời của Daniel, kể từ Scala 2.9, các phương thức breakbreakIfphương thức được chứa trong scala.tools.nsc.interpreter.ILoop. Ngoài ra, DebugParamlà bây giờ NamedParam.


Bạn sẽ cần thêm jline làm phụ thuộc.
schmmd

8
bạn có thể vui lòng viết một ví dụ với cách sử dụng mới?
Will

24

Ý TƯỞNG IntelliJ:

  1. Chạy ở chế độ gỡ lỗi hoặc đính kèm trình gỡ lỗi từ xa
  2. Đặt một điểm ngắt và chạy cho đến khi bạn đạt được nó
  3. Mở cửa sổ Evaluate Expression( Alt+ F8, trong menu: Chạy -> Đánh giá Biểu thức) để chạy mã Scala tùy ý.
  4. Nhập đoạn mã hoặc biểu thức bạn muốn chạy và nhấp vào Đánh giá
  5. Nhập Alt+ Vhoặc nhấp vào Đánh giá để chạy đoạn mã.

Nhật thực:

Kể từ Scala 2.10 cả hai breakbreakIfđã bị xóa khỏi ILoop.

Để tham gia phiên dịch, bạn sẽ phải làm việc ILooptrực tiếp với .

Đầu tiên hãy thêm scala compilerthư viện. Đối với Eclipse Scala, nhấp chuột phải vào dự án => Build Path=> Add Libraries...=> Scala Compiler.

Và sau đó, bạn có thể sử dụng phần sau khi bạn muốn bắt đầu trình thông dịch:

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

Trong Eclipse Scala, trình thông dịch có thể được sử dụng từ dạng Consolexem:


18
Thật kinh khủng. :(
Daniel C. Sobral

@Daniel Tại sao điều đó lại kinh khủng?
Hakkar

14
Bởi vì nó thêm rất nhiều boiler-plate mà hoàn toàn không liên quan đến mục tiêu gỡ lỗi tại một điểm trong chương trình, và thay vào đó, liên quan đến cơ chế bắt REPL.
Daniel C. Sobral

1
@Daniel có cách nào tốt hơn trong scala 2.10 không?
roterl

@roterl Vấn đề ở trên là gì?
Daniel C. Sobral
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.