我已经在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差异会影响我的类。
答案 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)
}
}