"Эвал" в Скала
Можно ли использовать Scala для написания скриптов в Java-приложении?
Мне нужно загрузить фрагмент кода Scala из Java, настроить для него область выполнения (данные, предоставляемые хост-приложением), оценить его и извлечь из него объект результата.
Документация Scala показывает, как легко вызывать скомпилированный код Scala из Java (потому что он превращается в обычный байт-код JVM).
Но как я могу оценить выражение Scala на лету (из Java или, если проще, изнутри Scala)?
Для многих других языков есть интерфейс javax.scripting. Похоже, что Scala его не поддерживает, и я не смог найти в документах по совместимости Java/Scala ничего, что не основывалось бы на преждевременной компиляции.
6 ответов
Scala не является языком сценариев. Он может выглядеть как язык сценариев, и люди могут защищать его для этой цели, но он не очень хорошо вписывается в среду сценариев JSR 223 (которая ориентирована на динамически типизированные языки). Чтобы ответить на ваш оригинальный вопрос, у Scala нет eval
функция так же, как Java не имеет eval
, Такая функция не имеет смысла ни для одного из этих языков, учитывая их статическую природу.
Мой совет: переосмыслите свой код так, чтобы он вам не понадобился eval
(Вы делаете это редко, даже на языках, где он есть, например на Ruby). В качестве альтернативы, возможно, вы вообще не хотите использовать Scala для этой части вашего приложения. Если вам действительно нужно eval
попробуйте использовать JRuby. JRuby, Scala и Java очень хорошо сочетаются друг с другом. Довольно легко иметь часть вашей системы в Java, часть в Scala и другую часть (часть, которая требует eval
в руби.
Сейчас 2011 год, и вы можете сделать это с scala.tools.nsc.Interpreter
см. http://blog.darevay.com/2009/01/remedial-scala-interpreting-scala-from-scala/
Scala добавил официальную поддержку JSR-223 в версии 2.11 ( https://issues.scala-lang.org/browse/SI-874).
Так что, если вам все еще это нужно, подумав о соображениях, изложенных в принятом в настоящее время ответе Даниэля Спевака (о переосмыслении таким образом, который не нужен), это должна быть официальная альтернатива.
Вы можете эмулировать "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
Я не уверен, если это хороший способ, но я решил эту проблему с помощью toolbox.parse
а также toolbox.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
Вы всегда можете использовать scalac для компиляции класса scala, а затем динамически загружать этот класс. Но я думаю, что это не то, что вы после.