首页 > 解决方案 > 为什么不能在 Kotlin 中将“`main`”函数声明为 lambda?

问题描述

以下简单的 Kotlin 代码片段

fun main() {}

编译得很好,但以下

val main : () -> Unit = {}

使编译器抱怨“在项目中找不到主要方法。”,而我希望它们是等效的(我希望编程语言在概念上尽可能统一)。

为什么会这样?它仅与 相关main,还是这种行为涉及更大的函数类?用 " " 声明函数和将它们声明为 lambdas之间有什么细微的区别fun吗?

标签: functionkotlinmethodslambdaanonymous-function

解决方案


从概念上讲,它们是不同的东西。为了看到这一点,让我们大致看一下等效的 Java 是什么。我将在此答案中使用 JVM 作为示例,但相同的原则适用于所有其他 Kotlin 后端。

object Foo {
  fun main() { ... }
}

这是大致

class Foo {
  public static void main() { ... }
}

再次,大致。从技术上讲,除非你使用,否则你会得到一个单例对象和一个方法@JvmStatic(我假设有一些特殊的处理main会在 JVM 上产生一个静态函数,但我不知道这是事实)

另一方面,

object Foo {
  val main: () -> Unit = { ... }
}

在这里,我们声明了一个属性,它在 Java 中将被实现为 getter-setter 对

class Foo {
  // Singleton instance
  public static Foo instance = new Foo();

  public Supplier<Void> main;

  Foo() {
    main = new Supplier<Void>() {
      Void get() {
        ...
      }
    }
  }

}

也就是说,实际上没有main方法。有一个main领域,在某处深处,里面有一个功能。在我上面的示例中,该函数称为get. 在 Kotlin 中,它被称为invoke.

我喜欢这样想。Kotlin 中的方法(即您在指定其行为的对象上定义的东西)本身并不是一流的对象。他们是存在于物体上的二等公民。您可以通过将它们转换为函数来将它们转换为一流的对象。函数是普通对象,就像其他任何对象一样。如果您使用一个普通对象(可能是也可能不是函数)并使用 调用它(),那么您实际上是在调用.invoke(...)它的方法。也就是说,()是真正最终调用方法的对象上的运算符。所以在 Kotlin 中,函数实际上只是具有自定义invoke和大量语法糖的对象。

val定义了一个作为函数的字段。你fun定义了一个方法。这两个都可以用 调用(),但只有一个是真正的方法调用;另一个在暗中呼唤.invoke另一个物体。它们在语法上看起来相同的事实是无关紧要的。

正如那句老话所说,功能是穷人的对象,对象是穷人的功能。


推荐阅读