"eval" в Scala

Может ли Scala использоваться script приложение Java?

Мне нужно загрузить кусок кода Scala из Java, настроить для него область выполнения (данные, представленные хост-приложением), оценить его и получить из него объект результата.

Документация Scala показывает, как легко вызвать скомпилированный код Scala из Java (поскольку он превращается в обычный байт-код JVM).

Но как я могу оценить выражение Scala на лету (от Java или, если это проще, изнутри Scala)?

Для многих других языков существует интерфейс javax.scripting. Scala, похоже, не поддерживает его, и я не смог найти что-либо в документах совместимости Java/Scala, которые не полагаются на компиляцию в режиме времени.

Ответ 1

Scala не является языком сценариев. Он может выглядеть как язык сценариев, и люди могут защищать его для этой цели, но он не очень хорошо вписывается в структуру сценариев JSR 223 (ориентированную на динамически типизированные языки). Чтобы ответить на ваш оригинальный вопрос, Scala не имеет функции eval, так же как Java не имеет eval. Такая функция не имеет смысла для любого из этих языков, учитывая их по своей сути статическую природу.

Мой совет: переосмыслите свой код, чтобы вам не нужно eval (вы редко это делаете, даже на языках, имеющих его, например Ruby). В качестве альтернативы, возможно, вы не хотите использовать Scala вообще для этой части вашего приложения. Если вам действительно нужно eval, попробуйте использовать JRuby. JRuby, Scala и Java-сетка очень красиво вместе. Очень легко иметь часть вашей системы на Java, часть в Scala и другую часть (бит, которая требует eval) в Ruby.

Ответ 3

Scala добавила официальную поддержку JSR-223 в 2.11 (https://issues.scala-lang.org/browse/SI-874).

Итак, если вы все еще нуждаетесь в этом, подумав о соображениях, высказанных в принятом в настоящее время ответе Даниэля Спивака (о переосмыслении таким образом, что это не нужно), это должно быть официальной альтернативой.

Ответ 4

Вы можете эмулировать "eval", взяв scala код, завернув его в класс, скомпилировав этот класс, используя отражение, чтобы создать новый экземпляр, а затем вызвав его. Это немного связано, а компилятор scala работает очень медленно (порядка 2 секунд) для инициализации, но он отлично работает.

Там есть библиотека, называемая "util-eval": https://github.com/twitter/util/

Этот код находится здесь: https://github.com/twitter/util/blob/master/util-eval/src/main/scala/com/twitter/util/Eval.scala

Он работает следующим образом:

val sum = Eval[Int]("1 + 1")
// sum will be 2

Ответ 5

Я не уверен, если это хороший способ, но я решил эту проблему с помощью toolbox.parse и toolbox.eval

Чтобы иметь eval в Scala, вам нужно:

  • Импорт scala -reflect

libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.7"

  1. Использовать eval из панели инструментов:

  import scala.reflect.runtime.currentMirror
  import scala.tools.reflect.ToolBox
  val toolbox = currentMirror.mkToolBox()

  val as = "2*(2+3)"
  val compe = toolbox.eval(toolbox.parse(as))

  println(compe.getClass) // prints class java.lang.Integer
  println(compe) // prints 10

Ответ 6

Вы всегда можете использовать scalac для компиляции класса scala, а затем динамически загружать этот класс. Но я думаю, это не то, что вам нужно.