无法在scala脚本中使用newInstance()

时间:2014-02-17 16:46:50

标签: scala

当像scala脚本一样运行以下内容时,我得到一个InstantiationException。但是当把它放在一个扩展App的类中,然后使用scalac进行编译并使用scala运行时,它可以工作。有什么想法吗?

class A
val foo = classOf[A]
foo.newInstance()

1 个答案:

答案 0 :(得分:1)

TL; DR 尝试foo.getConstructors()(0).newInstance(this),或使用您自己的multiline shebang


InstantiationException表明你的调用newInstance()正在调用一个不存在的构造函数。

这是一个类似的脚本,打印你的构造函数:

#!/bin/sh
exec scala "$0" "$@"
!#
class A
val foo = classOf[A]
foo.getConstructors.foreach(c => println("Constructor: " + c))

产:

Constructor: public Main$$anon$1$A(Main$$anon$1)

因此,必须将匿名类的实例传递给A的构造函数。

事实证明,Scala脚本由ScriptRunner运行,它使用匿名对象(改编自scala sourceProgramming Scala)包装脚本:

object Main {
  def main(args: Array[String]): Unit = {
    new AnyRef {
      // Your script code is inserted here.
    }
  }
}

因此,将外部匿名类this的实例传递给A的构造函数允许实例​​化内部类A的新实例。

据我所知,没有办法创建静态内部类within the scala language。基本脚本中的任何构造函数(由scala编译器创建)都需要外部实例。我所知道的其他选项包括字节码操作,以动态地为类创建新的构造函数(方式矫枉过正,imho)或重新实现ScriptRunner。

在shell脚本中的单个exec行期间,Scala实现了ScriptRunner:

    多行shebang的
  • Strips the header#!
  • 将您的代码包含在上面列出的匿名外部类模板中
  • 写一个临时的scala文件
  • 将scala文件编译为临时目录
  • 执行已编译的代码
  • 清理临时目录和脚本
  • 退出程序并退出代码

您可以使用您想要的任何语言编写自己的外部代码,然后在一行中exec外部代码。或者您可以使用多行shebang语法在脚本本身中嵌入功能,例如从this page上的Go示例改编的示例:

调试版本,通过sh -x打印命令,而不是实际删除任何内容:

#!/bin/sh -x
scriptfile=`basename $0`
classname="${scriptfile%.*}"
scalafile="${classname}.scala"
sed -e '1,12d' -e "s/%scala_class_name%/${classname}/" < "$0" > $scalafile
scalac $scalafile
echo todo: rm $scalafile
scala $classname "$@"
STATUS=$?
echo todo: rm "${classname}*.class"
exit $STATUS
######## Scala code starts on line 13
object %scala_class_name% {
    def main(args: Array[String]) {
        class A
        val foo = classOf[A]
        println(foo.newInstance())
    }
}

我包含调试版本的原因是您可能只想将此作为起点。例如,根据脚本中的其他内容,可能需要进行更多设置或清理,包括:

  • 编辑jvm args,包括类路径
  • 如果脚本中有多个类
  • ,则创建一个完整的临时目录
  • 更多sed / awk嵌入式scala本身取决于传入的参数

那里说的是“它应该起作用,但我不保证”以上的版本,它会自行清理:

#!/bin/sh
scriptfile=`basename $0`
classname="${scriptfile%.*}"
scalafile="${classname}.scala"
sed -e '1,12d' -e "s/%scala_class_name%/${classname}/" < "$0" > $scalafile
scalac $scalafile
rm $scalafile
scala $classname "$@"
STATUS=$?
rm "${classname}*.class"
exit $STATUS
######## Scala code starts on line 13
object %scala_class_name% {
    def main(args: Array[String]) {
        class A
        val foo = classOf[A]
        println(foo.newInstance())
    }
}

引用:

链接到商业书籍的利益冲突免责声明:

原始回答者不适用于Oreilly,但却是一个狂热的消费者。 ;)