绑定Scala Interpreter中的实例时的类路径问题

时间:2013-08-28 19:01:02

标签: scala binding classpath interpreter

我已经在scala lang论坛发布了这个问题,但遗憾的是我没有得到任何答案。 第二次机会?

我尝试将一个解释器和一个scala片段嵌入到这个解释器中。我想在解释器中绑定一个自定义类的实例。总结一下看起来像:

import scala.tools.nsc._
import scala.tools.nsc.interpreter._

class C {
  def sayHello(s:String) = "hello "+s
}

object Main extends App {

 val c= new C

 val s = new Settings
 s.usejavacp.value=true

 val i = new IMain(s)
 i.bind("myC",c)
 i.bind("world","the world")

 val script = "println(myC.sayHello(world))"
 i.eval(script)   

}

当我在Eclipse(Kepler)中运行此代码片段时 - OpenJDK6 / 7适用于两者 - BSD OS Scala-2.11.0-M4 - scala-compiler.jar在路径中工作正常 如果我尝试在repl中运行相同的代码或直接使用scalac file.scala然后scala -cp。主要我得到以下错误

    error: not found value myC
    javax.script.ScriptException: compile-time error
    at scala.tools.nsc.interpreter.IMain.compile(IMain.scala:575)
    at scala.tools.nsc.interpreter.IMain.eval(IMain.scala:997)
    at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)

我能够在另一个操作系统(Win7)下工作,但是添加了s.bootclasspath =" path / to / my / classes"

我怀疑有一些类路径问题

后来我通过这种方式用java调用替换scala命令行调用来运行它: 包含scala库的CLASSPATH的java -cp $CLASSPATH Main

我查看了scala命令,它就像是以不同的方式在scpath库中附加了scala库。

有人有任何建议吗?

由于

根据以下评论添加:

Scalac不输出任何错误 事实上,如果我跑:

  java -cp .:$SCALA_PATH/lib/scala-library.jar:$SCALA_PATH/lib/scala-compiler.jar:$SCALA_PATH/lib/scala-reflect.jar Main

或建议scala -nobootcp它的工作原理(感谢宝贵的建议) 否则,如果我让scala使用bootcp,则启动的行是以下的行,它将失败

  java -Xbootclasspath/a:/usr/home/pcohen/Dev/Scala/scala-2.11.0-M4/lib/akka-actors.jar[...] -classpath "" [...]

当scala jar附加到bootclasspath时,就像我的绑定失败一样。我无法清楚地理解为什么这个bootclasspath差异会影响我的类。

1 个答案:

答案 0 :(得分:3)

我不知道这是否符合建议的要求,但您知道吗:

scala> class C { def sayHello(s: String) = s"hello, $s" }
defined class C

scala> $intp.bind("world","the world")
world: String = the world
res0: scala.tools.nsc.interpreter.IR.Result = Success

scala> val c = new C
c: C = C@19878659

scala> $intp interpret "c sayHello world"
res2: String = hello, the world
res1: scala.tools.nsc.interpreter.IR.Result = Success

通过单独编译,您的示例适用于scala -nobootcp my.Main

您可以使用-Dscala.repl.debug=true查看更多内容。您会看到Error的{​​{1}}返回(每个人检查结果值,对吗?bind)由以下原因引起:

println(i.bind("myC",c))

以及尝试它的包装器代码。

更多的话:

你说,“这就像我的绑定失败了”,但正如我在上面所说,这正是绑定失败。

原因是当你说“绑定”时,你的意思是“自动生成一些代码,就像我写的那样,java.lang.ClassCastException: intpbind.C cannot be cast to intpbind.C。”哦,然后编译它,然后使scala> val myC = c成为可以由REPL会话的其余部分导入的符号。

当您使用引导类路径上的REPL编译该代码时,引导类路径必须能够看到您的类myC。 (它也必须是由应用程序类加载器加载的同一个类,加载主类的类;通常由于委托而实现。)

所以,这有效:

C

你可以通过在引导类路径中只放置一些类来实现细微差别,或者更有可能的是,你将按照我的建议进行操作并将scala从引导类路径中删除。

我还没有对此进行过研究,但你可以使用嵌入在托管环境中的REPL来解决类似问题的人们,因为你所居住的类加载器非常重要。

奖金效用:

scalac -d /tmp/out mytest.scala
scala -J-Xbootclasspath/a:/tmp/out mytest.Test

使用scala-private实用程序来转储您感兴趣的类加载器:

package scala {
  package object foo {
    def show(cl: ClassLoader): String = scala.reflect.runtime.ReflectionUtils.show(cl)
  }
}