如何在运行时使用 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>
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>