我正在学习Scala并尝试编写一些命令行可执行文件。
我有两个版本的HelloWorld,我认为它在语义上是相同的。 HelloWorld.scala
从命令行成功编译并运行。 HelloWorld2.scala
编译但产生运行时错误。
我的问题:我认为两者在语义上是相同的,那么为什么第二个会产生运行时错误呢?
以下是工作示例:
// HelloWorld.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, World!")
}
}
这是一个破碎的例子:
// HelloWorld2.scala
object HelloWorld2 {
def main
: Array[String] => Unit
= args => {
println("Hello, World!")
}
}
这是控制台输出:
java.lang.NoSuchMethodException: HelloWorld2.main([Ljava.lang.String;)
at java.lang.Class.getMethod(Class.java:1778)
at scala.reflect.internal.util.ScalaClassLoader$class.run(ScalaClassLoader.scala:66)
at scala.reflect.internal.util.ScalaClassLoader$URLClassLoader.run(ScalaClassLoader.scala:101)
at scala.tools.nsc.CommonRunner$class.run(ObjectRunner.scala:22)
at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:39)
at scala.tools.nsc.CommonRunner$class.runAndCatch(ObjectRunner.scala:29)
at scala.tools.nsc.ObjectRunner$.runAndCatch(ObjectRunner.scala:39)
at scala.tools.nsc.MainGenericRunner.runTarget$1(MainGenericRunner.scala:65)
at scala.tools.nsc.MainGenericRunner.run$1(MainGenericRunner.scala:87)
at scala.tools.nsc.MainGenericRunner.process(MainGenericRunner.scala:98)
at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:103)
at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)
答案 0 :(得分:5)
无论scala如何将方法转换为函数(使用eta-expansion,有时是自动扩展),他们都会different things在这里。主要区别在于scala为JVM生成不同的字节码。
谈到你的例子,你实际上定义了一个返回类Function1
的对象的方法def
:
def main: Function1[Array[String], Unit] //you could even put `val` here
当JVM需要具有完全不同签名的方法时:
def main(args: Array[String]): Unit
因为对于JVM,函数只是类FunctionN
的一个实例,所以scala编译器不会自动将它转换为方法。手动转换如下:
def main(args: Array[String]): Unit = main.apply(args)
def main: Array[String] => Unit = ...// or `val main`
请注意,apply
只是Function1
类的一种方法,()
只是调用apply
的语法糖。
更新
只是一个额外的信息。正如@ som-snytt指出的那样,scala
的跑步者对main
的签名更加灵活,所以这个:
def main(args: Array[String]): Int
适用于scala HelloWorld
,但不会为java HelloWorld
工作 - 它需要Unit
(void
)作为返回类型。我还记得使用javac
与scalac
编译Java代码之间的一些区别。所以重点是scala
/ scalac
正在发展,因此scala
可能(将来)可以运行更轻松的main
方法,例如功能接口或一些东西。它还可以编译和运行脚本,顺便说一句。