"Использование 'eval' в Scala"
Может ли Scala использоваться для скриптинга Java-приложения?
Мне нужно загрузить участок кода на Scala из Java, установить для него контекст выполнения (данные, предоставленные основной программой), оценить его и получить объект результата.
Документация по Scala демонстрирует, насколько легко вызывать скомпилированный код Scala из Java, поскольку он преобразуется в обычный байт-код JVM.
Но как я могу оценивать выражение на Scala "на лету" (из Java или, если это проще, из самой Scala)?
Для многих других языков существует интерфейс javax.scripting. Однако, похоже, что Scala не поддерживает его, и я не смог найти ничего в документации по совместимости Java/Scala, что не полагалось бы на компиляцию заранее.
4 ответ(ов)
Scala добавила официальную поддержку JSR-223 в версии 2.11 (https://issues.scala-lang.org/browse/SI-874).
Если после размышлений над доводами, приведенными в уже принятых ответах от Дэниела Спивека (касательно переосмысления необходимости использования этого подхода), вам все еще нужна эта поддержка, то это должно быть официальной альтернативой.
Scala не является языком сценариев. Хотя он может выглядеть как сценарный язык, и некоторые могут рекомендовать его для этого, на самом деле он не вписывается в рамки JSR 223, который ориентирован на динамически типизированные языки. В ответ на ваш первоначальный вопрос: у Scala нет функции eval
, так же как и у Java. Такая функция не имеет особого смысла для этих языков из-за их статической природы.
Мой совет: пересмотрите свой код так, чтобы вам не понадобилась функция eval
(обычно она не нужна, даже в языках, где она есть, как, например, в Ruby). В качестве альтернативы, возможно, вам не следует использовать Scala для этой части вашего приложения. Если вам действительно необходимо использовать eval
, попробуйте JRuby. JRuby, Scala и Java прекрасно сочетаются друг с другом. Вам будет достаточно легко разделить свою систему на части: одну на Java, другую на Scala и еще одну (ту, которая требует eval
) на Ruby.
Я не уверен, что это лучший способ, но я решил эту задачу, используя toolbox.parse
и toolbox.eval
.
Чтобы выполнить выражение в Scala, необходимо:
- Импортировать
scala-reflect
. Добавьте следующую зависимость в вашbuild.sbt
:
libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.7"
- Использовать
eval
изtoolbox
:
import scala.reflect.runtime.currentMirror
import scala.tools.reflect.ToolBox
val toolbox = currentMirror.mkToolBox()
val as = "2*(2+3)"
val result = toolbox.eval(toolbox.parse(as))
println(result.getClass) // выводит class java.lang.Integer
println(result) // выводит 10
Таким образом, вы сможете динамически оценивать строковые выражения в Scala.
Вы всегда можете использовать scalac для компиляции Scala-класса, а затем динамически загрузить этот класс. Но, думаю, это не то, что вы ищете.
Как сопоставить любой символ на нескольких строках в регулярном выражении?
Что значит 'synchronized'?
Почему нет ConcurrentHashSet, если есть ConcurrentHashMap?
Как объявить массив в одну строку?
Какие проблемы следует учитывать при переопределении equals и hashCode в Java?