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

时间:2015-03-12 13:24:44

标签: xml scala reflection eval

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$2.apply(ToolBoxFactory.scala:429)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$$anonfun$compile$2.apply(ToolBoxFactory.scala:422)
  at scala.tools.reflect.ToolBoxFactory$ToolBoxImpl$withCompilerApi$.liftedTree2$1(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是什么意思?

1 个答案:

答案 0 :(得分:3)

这可能与以下事实有关: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中的运行时Universe创建)也找不到它也就不足为奇了(甚至在REPL之外也可能存在同样的问题)。 这可能可能被归类为错误(至少应该被报告),但至少有一个丑陋但简单的解决方法:

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

当然,您实际上想要修改eval本身以抽象出这个黑客:

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>