Scala:导致运行时错误的语法?

Scala: Syntax causing runtime error?

我正在学习 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(MainGenericRunner.scala:65)
    at scala.tools.nsc.MainGenericRunner.run(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)

尽管 scala 可以将方法转换为函数(使用 eta 扩展,有时是自动的),但它们 different things 在这里。主要区别在于 scala 为 JVM 生成不同的字节码。

谈到你的例子,你实际上定义了一个方法def,return是class的一个对象Function1:

def main: Function1[Array[String], Unit] //you could even put `val` here

当 JVM 需要一个具有完全不同签名的方法时:

def main(args: Array[String]): Unit

因为对于 JVM,函数只是 class FunctionN 的实例,scala 编译器不会自动将其转换为方法。手动转换如下所示:

def main(args: Array[String]): Unit = main.apply(args)

def main: Array[String] => Unit = ...// or `val main`

注意apply只是Function1的一个方法class,()只是调用apply的语法糖。

更新:

只是补充信息。正如@som-snytt 指出的那样,scalas 运行ner 对 main 的签名更加灵活,因此:

def main(args: Array[String]): Int

将适用于 scala HelloWorld,但不适用于 java HelloWorld - 它需要 Unit (void) 作为 return 类型。我还记得使用 javacscalac 编译 Java 代码之间的一些差异。所以重点是 scala/scalac 正在发展,因此(将来)scala 到 运行 更宽松的 main 方法可能是可能的,比如也许是功能接口之类的。它还可以编译 运行 脚本,顺便说一句。