微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

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

以下简单的 Kotlin 代码片段

fun main() {}

编译得很好,但以下内容

val main : () -> Unit = {}

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

为什么会这样?它仅与 main 相关,还是这种行为涉及更大的函数类?有subtle difference between declaring functions with "fun" and declaring them as 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(...)。也就是说,() 是对象上的 operator,它实际上最终调用了一个方法。因此,在 Kotlin 中,函数实际上只是具有自定义 invoke 和大量语法糖的对象。

您的 val 定义了一个字段,它是一个函数。您的 fun 定义了一个方法。这两个都可以用()调用,但只有一个是真正的方法调用;另一个正在秘密调用另一个对象上的 .invoke。它们在语法上看起来相同这一事实无关紧要。

正如古老的格言所说,函数是穷人的对象,对象是穷人的函数。

,

存在细微(或不止细微)的差异。用 val 声明它意味着 main 是一个包含对匿名函数(您用 lambda 定义)的引用的属性。如果用val来定义,那么当你调用main()时,实际上是在调用main属性的getter,然后使用invoke()运算符调用{{ 1}} 属性的返回值(匿名函数)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。