【问题标题】:Why can't the "`main`" function be declared as a lambda in Kotlin?为什么不能在 Kotlin 中将“`main`”函数声明为 lambda?
【发布时间】:2021-07-02 19:10:51
【问题描述】:

以下琐碎的 Kotlin 代码 sn-p

fun main() {}

编译得很好,但是下面

val main : () -> Unit = {}

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

为什么会这样?它仅与main 相关,还是这种行为涉及更大的函数类?有subtle difference between declaring functions with "fun" and declaring them as lambdas吗?

【问题讨论】:

    标签: function kotlin methods lambda anonymous-function


    【解决方案1】:

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

    俗话说,功能是穷人的对象,对象是穷人的功能。

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 我在 Scala 中注意到了同样的行为;它的解释和 Kotlin 中的一样吗?
      • 我没有任何 Scala 经验。但如果他们对属性有相同的概念,那很可能是相同的概念。
      猜你喜欢
      • 2010-09-24
      • 2018-03-28
      • 2016-04-18
      • 1970-01-01
      • 2011-08-27
      • 2011-07-03
      • 1970-01-01
      • 2016-05-20
      相关资源
      最近更新 更多