如何在运行时使用 scala.tools.reflect.ToolBox 评估 xml 文字?

How to evalulate xml literal using scala.tools.reflect.ToolBox in runtime?

Welcome to Scala version 2.11.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_25).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.reflect.runtime.currentMirror
import scala.reflect.runtime.currentMirror

scala> import scala.tools.reflect.ToolBox
import scala.tools.reflect.ToolBox

scala> def eval(code: String) = {
     |   val toolbox = currentMirror.mkToolBox()
     |   toolbox.eval(toolbox.parse(code))
     | }
eval: (code: String)Any

scala> eval("1 + 2")
res0: Any = 3

scala> eval("<a>b</a>")
scala.tools.reflect.ToolBoxError: reflective compilation has failed:

not found: value $scope
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.throwIfErrors(ToolBoxFactory.scala:316)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.wrapInPackageAndCompile(ToolBoxFactory.scala:198)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$ToolBoxGlobal.compile(ToolBoxFactory.scala:252)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile.apply(ToolBoxFactory.scala:429)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile.apply(ToolBoxFactory.scala:422)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2(ToolBoxFactory.scala:355)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.apply(ToolBoxFactory.scala:355)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.compile(ToolBoxFactory.scala:422)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl.eval(ToolBoxFactory.scala:444)
  at .eval(<console>:11)

not fould: value $scope是什么意思?

这可能与 XML 从 scala 2.11 开始在单独的库中提取支持有关,因为在 scala 2.10 中尝试您的代码片段非常有效。

好像找不到$scope: scala.xml.TopScope.

在 scala 2.10.* 中,定义在 Predef.

从 scala 2.11.0 开始,编译器不能期望此值始终可用,因为您必须显式包含 xml 库。 考虑到这一点,我们可能想知道工具箱是否可以访问 xml 库。我们知道它可以在 REPL 中访问(它是自动导入的),这很容易检查:

scala> xml.Text("foo")
res18: scala.xml.Text = foo
scala> <a>b<a>
res19: scala.xml.Elem = <a>b</a>

但是,$scope本身是否可以访问?

scala> $scope
<console>:13: error: not found: value $scope
              $scope
              ^

糟糕。为什么它不可访问,老实说我不知道​​,但我认为实际上甚至在 xml 库中的任何地方都没有任何 $scope 值,而且这个值是由编译器神奇地合成的。这种魔法似乎在工具箱中失效了。 作为参考,如果您在 scala 2.10.0 中尝试相同的操作,它工作正常:

scala> $scope
res2: xml.TopScope.type =

无论如何,这显然是问题的根源。如果 REPL 本身找不到 $scope ,工具箱(从 REPL 内部的运行时宇宙创建)也找不到它也就不足为奇了(即使在 REPL 之外也可能存在同样的问题)。 这可以可能归类为错误(并且至少应该报告),但至少有一个丑陋但简单的解决方法:

scala> eval("val $scope = scala.xml.TopScope; <a>b</a>")
res22: Any = <a>b</a>

当然你实际上想要修改 eval 本身来抽象掉这个 hack:

def eval(code: String) = {
  val toolbox = currentMirror.mkToolBox()
  toolbox.eval(toolbox.parse("val $scope = scala.xml.TopScope; " + code))
}

现在看:

scala> eval("<a>b</a>")
res24: Any = <a>b</a>