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

时间:2016-07-25 04:31:54

标签: scala syntax semantics

我正在学习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)

1 个答案:

答案 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工作 - 它需要Unitvoid)作为返回类型。我还记得使用javacscalac编译Java代码之间的一些区别。所以重点是scala / scalac正在发展,因此scala可能(将来)可以运行更轻松的main方法,例如功能接口或一些东西。它还可以编译和运行脚本,顺便说一句。