[英]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.