Kotlin 1.4 中的函数接口
Function interface in Kotlin 1.4
此功能即将推出 Kotlin 1.4
。这是 KotlinConf'19
.
的摘录
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
runAction{
println("Hello")
}
看起来不错,就是不知道有什么用
函数接口是什么?它的实用价值是什么?具体可以用于哪些场景?
这是关于功能接口 — 具有单一抽象方法的接口(也称为 SAM 接口)。
为了理解这一点,我需要回顾一下历史……在 Java 中,lambda 是最近才添加的。在此之前,您通过实现合适的接口来实现回调等。例如,如果您想在 AWT 组件被操作时得到通知,您将创建一个实现 ActionListener
接口的对象。它只有一个方法(称为 actionPerformed()
);你会把你的代码放在那个方法里:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do something
}
});
当他们添加 lambda 时,他们希望融入所有现有代码,并尽可能少地进行更改,因此他们采用完全相同的方式:编译器推断您正在实现的接口,并创建一个实现该接口的对象。你可以这样写:
myButton.addActionListener(e -> {
// Do something
});
它更短 — 但它编译后与第一个示例几乎相同。
所以在Java中,函数不是first-class对象; lambdas 只是一种更简洁的实现功能接口的方法。
然而,在 Kotlin 中,函数 是 first-class 对象:您可以自己编写一个 lambda(或匿名函数),分配它,传递它到函数,return 它从函数,等等 — 所以根本不需要 SAM 接口!
为了更轻松地与 Java 进行互操作,Kotlin 让您可以轻松实现 Java SAM 接口,就像在 Java:
中一样
myButton.addActionListener {
// Do something
}
但是 Kotlin <= 1.3 不允许您以这种方式实现 Kotlin 接口;您需要明确实施这些。 (我怀疑这在一定程度上是为了鼓励开发人员使用具有所有其他优势的适当功能,而不是依赖于 Java 风格的解决方法。)
你的例子说明了这一点。它有一个接口(Action
)和一个抽象方法(run()
)。它有一个函数(runAction()
),它接受该接口的一个实例。它有一些代码想要调用该函数,只传递 run()
方法的代码。
在 Kotlin <= 1.3 中,您必须明确地执行后者,例如:
runAction(object : Action {
override fun run() {
println("Hello")
}
})
但是从 Kotlin 1.4 开始,您可以将界面标记为 fun interface
,并使用 Java 样式的快捷方式,如您的示例所示。
(你可能认为这是好事,也可能不认为……)
此功能即将推出 Kotlin 1.4
。这是 KotlinConf'19
.
fun interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
runAction{
println("Hello")
}
看起来不错,就是不知道有什么用
函数接口是什么?它的实用价值是什么?具体可以用于哪些场景?
这是关于功能接口 — 具有单一抽象方法的接口(也称为 SAM 接口)。
为了理解这一点,我需要回顾一下历史……在 Java 中,lambda 是最近才添加的。在此之前,您通过实现合适的接口来实现回调等。例如,如果您想在 AWT 组件被操作时得到通知,您将创建一个实现 ActionListener
接口的对象。它只有一个方法(称为 actionPerformed()
);你会把你的代码放在那个方法里:
myButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Do something
}
});
当他们添加 lambda 时,他们希望融入所有现有代码,并尽可能少地进行更改,因此他们采用完全相同的方式:编译器推断您正在实现的接口,并创建一个实现该接口的对象。你可以这样写:
myButton.addActionListener(e -> {
// Do something
});
它更短 — 但它编译后与第一个示例几乎相同。
所以在Java中,函数不是first-class对象; lambdas 只是一种更简洁的实现功能接口的方法。
然而,在 Kotlin 中,函数 是 first-class 对象:您可以自己编写一个 lambda(或匿名函数),分配它,传递它到函数,return 它从函数,等等 — 所以根本不需要 SAM 接口!
为了更轻松地与 Java 进行互操作,Kotlin 让您可以轻松实现 Java SAM 接口,就像在 Java:
中一样myButton.addActionListener {
// Do something
}
但是 Kotlin <= 1.3 不允许您以这种方式实现 Kotlin 接口;您需要明确实施这些。 (我怀疑这在一定程度上是为了鼓励开发人员使用具有所有其他优势的适当功能,而不是依赖于 Java 风格的解决方法。)
你的例子说明了这一点。它有一个接口(Action
)和一个抽象方法(run()
)。它有一个函数(runAction()
),它接受该接口的一个实例。它有一些代码想要调用该函数,只传递 run()
方法的代码。
在 Kotlin <= 1.3 中,您必须明确地执行后者,例如:
runAction(object : Action {
override fun run() {
println("Hello")
}
})
但是从 Kotlin 1.4 开始,您可以将界面标记为 fun interface
,并使用 Java 样式的快捷方式,如您的示例所示。
(你可能认为这是好事,也可能不认为……)