Scriptengine 将脚本结果传递给Scala 2.11脚本引擎中的主程序

Scriptengine 将脚本结果传递给Scala 2.11脚本引擎中的主程序,scriptengine,scala-2.11,Scriptengine,Scala 2.11,使用2.11 Milestone 7中的Scala脚本引擎,如何从脚本引擎中获取类型化值?我收到错误消息,如mypackage.Holler无法转换为mypackage.Holler 下面是简化为要点的用例。我想使用脚本来准备和配置我将在主程序中处理的标准类型的对象。我有一个特点: package mypackage trait Holler { def shout: Unit } 我在Scala中有一个用户脚本,保存在文件/home/me/Foo.Scala中 object Foo e

使用2.11 Milestone 7中的Scala脚本引擎,如何从脚本引擎中获取类型化值?我收到错误消息,如mypackage.Holler无法转换为mypackage.Holler

下面是简化为要点的用例。我想使用脚本来准备和配置我将在主程序中处理的标准类型的对象。我有一个特点:

package mypackage

trait Holler {
  def shout: Unit
}
我在Scala中有一个用户脚本,保存在文件/home/me/Foo.Scala中

object Foo extends mypackage.Holler {
  def shout: Unit = println("Hello World!")
}
当我使用IMain.evalReader运行此脚本时,我希望返回对象Foo,因为它是最后一条语句的结果。下面是一个程序,包括两个运行脚本的有用打印输出:

package mypackage

import javax.script.ScriptEngineManager
import scala.tools.nsc.interpreter.IMain

object Runner {
  def main(args: Array[String]): Unit = {
    //  Create the script engine
    val javaxEngine = new ScriptEngineManager().getEngineByName("scala")
    val scalaEngine = javaEngine.asInstanceOf[IMain]

    // Configure script engine to use the Java classpath
    val useJavaClassPath = scalaEngine.settings.usejavacp.tryToSet(List("true"))
    println("Use Java CP? " + useJavaClassPath)

    val script = new java.io.FileReader("/home/me/Foo.scala")
    val result = scalaEngine.eval(script)
    println("Script Result Type: " + result.getClass.getName)
    println("Defined Symbols: " + scalaEngine.definedSymbolList)
    val myHoller = result.asInstanceOf[mypackage.Holler]
  }
}
Foo.shout
val result: Holler = Foo
脚本在脚本引擎下运行正常。但这一结果不可能让人大喊大叫。该程序的输出如下:

Use Java CP? Some(List(true))
Script Result Type: $line3.$read$$iw$$iw$Foo$
Defined Symbols: List(value engine, object iw$Foo)
Exception in thread "main" java.lang.ClassCastException: $line3.$read$$iw$$iw$Foo$ cannot be cast to mypackage.Holler
这告诉我脚本引擎成功地识别了类路径,并且正在构造Foo对象。但是脚本中公共类路径中的trait mypackage.Holler与主程序中的trait mypackage.Holler不同

如果我向脚本中添加以下行:

package mypackage

import javax.script.ScriptEngineManager
import scala.tools.nsc.interpreter.IMain

object Runner {
  def main(args: Array[String]): Unit = {
    //  Create the script engine
    val javaxEngine = new ScriptEngineManager().getEngineByName("scala")
    val scalaEngine = javaEngine.asInstanceOf[IMain]

    // Configure script engine to use the Java classpath
    val useJavaClassPath = scalaEngine.settings.usejavacp.tryToSet(List("true"))
    println("Use Java CP? " + useJavaClassPath)

    val script = new java.io.FileReader("/home/me/Foo.scala")
    val result = scalaEngine.eval(script)
    println("Script Result Type: " + result.getClass.getName)
    println("Defined Symbols: " + scalaEngine.definedSymbolList)
    val myHoller = result.asInstanceOf[mypackage.Holler]
  }
}
Foo.shout
val result: Holler = Foo
我明白了:

正在练习的呼喊方法Hello World!打印出来, 结果将添加到已定义符号的列表中 结果与Holler型完全一致。 我可以将catcher对象绑定到脚本引擎。其代码如下所示:

package mypackage

class Catcher {
  var item: Holler = null
}
而我与

val mycatcher = new Catcher
scalaEngine.bind("catcher", mycatcher)
scalaEngine.eval("catcher = Foo")
现在catcher出现在脚本引擎的已定义符号列表中,我可以使用catcher进入脚本引擎,并使用如下命令

scalaScriptEngine.eval("catcher.item = result")
但是我得到了奇怪的编译时类异常,说:

mypackage.Holler cannot be cast to mypackage.Holler
如果我将Catcher中的项目设置为Any,那么在设置之前我不会得到异常

mycatcher.item.asInstanceOf[Holler]

在主程序中。但我还是得到了几乎相同的例外。这就好像两个不兼容的类加载器被用于同一个类路径。那么,如何从主程序访问Foo对象作为Holler的实例,它在脚本引擎中明确实现了这一点?

这看起来有点像类加载器问题:是否在程序中加载Holler类的类加载器与在编译器中创建Holler类的类加载器不同?不幸的是,整个嵌入式编译/脚本编写过程都非常缺乏文档,Scala开发人员似乎从来都懒得回答有关它的问题。因此,我基本上放弃了使用Scala作为嵌入式语言。如果某个东西的文档记录如此糟糕,而且使用起来如此复杂,那么它很可能在不久的将来就会崩溃。