"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.
Ответ 2
теперь в 2011 году, и вы можете сделать это с помощью scala.tools.nsc.Interpreter
см. http://blog.darevay.com/2009/01/remedial-scala-interpreting-scala-from-scala/
Ответ 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, вам нужно:
libraryDependencies += "org.scala-lang" % "scala-reflect" % "2.11.7"
- Использовать 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, а затем динамически загружать этот класс. Но я думаю, это не то, что вам нужно.