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 指出的那样,scala
s 运行ner 对 main
的签名更加灵活,因此:
def main(args: Array[String]): Int
将适用于 scala HelloWorld
,但不适用于 java HelloWorld
- 它需要 Unit
(void
) 作为 return 类型。我还记得使用 javac
与 scalac
编译 Java 代码之间的一些差异。所以重点是 scala
/scalac
正在发展,因此(将来)scala
到 运行 更宽松的 main
方法可能是可能的,比如也许是功能接口之类的。它还可以编译 运行 脚本,顺便说一句。
我正在学习 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 指出的那样,scala
s 运行ner 对 main
的签名更加灵活,因此:
def main(args: Array[String]): Int
将适用于 scala HelloWorld
,但不适用于 java HelloWorld
- 它需要 Unit
(void
) 作为 return 类型。我还记得使用 javac
与 scalac
编译 Java 代码之间的一些差异。所以重点是 scala
/scalac
正在发展,因此(将来)scala
到 运行 更宽松的 main
方法可能是可能的,比如也许是功能接口之类的。它还可以编译 运行 脚本,顺便说一句。