繁体   English   中英

为什么不能在 Kotlin 中将“`main`”函数声明为 lambda?

[英]Why can't the “`main`” function be declared as a lambda in Kotlin?

以下简单的 Kotlin 代码片段

fun main() {}

编译得很好,但以下

val main : () -> Unit = {}

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

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

从概念上讲,它们是不同的东西。 为了看到这一点,让我们大致看一下等效的 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 它们在语法上看起来相同的事实是无关紧要的。

正如一句古老的谚语所说,函数是穷人的对象,对象是穷人的函数。

有一个微妙的(或不仅仅是微妙的)差异。 val声明它意味着main是一个包含对匿名函数(您用 lambda 定义)的引用的属性。 如果你用val定义它,那么当你调用main() ,你实际上是在调用main属性的 getter,然后使用invoke()操作符在属性的返回值上调用invoke() (匿名函数)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM