如何在运行时编译/评估 Scala 表达式? [英] How to compile/eval a Scala expression at runtime?

查看:46
本文介绍了如何在运行时编译/评估 Scala 表达式?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Scala 新手,正在寻找指向惯用解决方案的指针(如果有).

New to Scala and looking for pointers to an idiomatic solution, if there is one.

我希望将用户提供的任意 Scala 函数(允许引用我在代码中定义的函数/类)应用于某些数据.

I'd like to have arbitrary user-supplied Scala functions (which are allowed to reference functions/classes I have defined in my code) applied to some data.

例如:我在 myprog.scala<中定义了 foo(s: String): Stringbar(s: String): String 函数/代码>.用户像这样运行我的程序:

For example: I have foo(s: String): String and bar(s: String): String functions defined in my myprog.scala. The user runs my program like this:

$ scala myprog data.txt --func='(s: Str) => foo(bar(s)).reverse'

这将逐行运行数据文件,并发出将用户指定的函数应用于该行的结果.

This would run line by line through the data file and emit the result of applying the user-specified function to that line.

为了加分,我可以确保用户定义的函数中没有副作用吗?如果不是,我是否可以限制该函数使用一个受限的函数子集(我可以保证是安全的)?

For extra points, can I ensure that there are no side-effects in the user-defined function? If not, can I restrict the function to use only a restricted subset of functions (which I can assure to be safe)?

推荐答案

@kenjiyoshida 有一个很好的 gist 展示了如何评估 Scala 代码.请注意,当使用该要点中的 Eval 时,当 Scala 默认推断 Nothing 时,不指定返回值将导致运行时失败.

@kenjiyoshida has a nice gist that shows how to eval Scala code. Note that when using Eval from that gist, not specifying a return value will result in a runtime failure when Scala defaults to inferring Nothing.

scala> Eval("println(\"Hello\")")
Hello
java.lang.ClassCastException: scala.runtime.BoxedUnit cannot be cast to scala.runtime.Nothing$
  ... 42 elided

对比

scala> Eval[Unit]("println(\"Hello\")")
Hello

它也可以很好地处理范围内的任何内容.

It nicely handles whatever's in scope as well.

 object Thing {
   val thing: Int = 5
 }

 object Eval {

   def apply[A](string: String): A = {
     val toolbox = currentMirror.mkToolBox()
     val tree = toolbox.parse(string)
     toolbox.eval(tree).asInstanceOf[A]
   }

   def fromFile[A](file: File): A =
     apply(scala.io.Source.fromFile(file).mkString(""))

   def fromFileName[A](file: String): A =
     fromFile(new File(file))

 }

 object Thing2 {
   val thing2 = Eval[Int]("Thing.thing") // 5
 }

Twitter 的 util 包曾经有 util-eval,但现在似乎已被弃用(并且在编译时也会触发编译器错误).

Twitter's util package used to have util-eval, but that seems to have been deprecated now (and also triggers a compiler bug when compiled).

至于你问题的第二部分,答案似乎是否定的.即使您禁用默认的 Predef 并自行导入,用户始终可以使用完全限定的包名称访问这些功能.您也许可以使用 Scala 的 scala.tools.reflect.ToolBox 来首先解析您的字符串,然后在传递给 eval 之前与白名单进行比较,但此时事情可能会变得非常麻烦,因为您将手动编写代码来清理 Scala AST(或至少拒绝危险输入).这绝对不是一个惯用的解决方案".

As for the second part of your question, the answer seems to be no. Even if you disable default Predef and imports yourself, a user can always get to those functions with the fully qualified package name. You could perhaps use Scala's scala.tools.reflect.ToolBox to first parse your string and then compare against a whitelist, before passing to eval, but at that point things could get pretty hairy since you'll be manually writing code to sanitize the Scala AST (or at the very least reject dangerous input). It definitely doesn't seem to be an "idiomatic solution."

这篇关于如何在运行时编译/评估 Scala 表达式?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆