首页 > 解决方案 > Kotlin 1.4 中的函数接口

问题描述

此功能即将推出Kotlin 1.4。这里是摘录自KotlinConf'19

fun interface Action {
    fun run()
}

fun runAction(a: Action) = a.run()

runAction{
    println("Hello")
}

它看起来不错,但我仍然不知道它的作用。

什么是功能接口?它的实用价值是什么?它可以用于哪些具体场景?

标签: kotlinfunctional-interface

解决方案


这是关于功能接口——与单一抽象方法的接口(也称为 SAM 接口)。

为了理解这一点,我需要介绍一些历史……在 Java 中,lambda 是最近才添加的。在此之前,您通过实现合适的接口来实现回调和类似的。例如,如果您想在 AWT 组件被操作时得到通知,您将创建一个实现该ActionListener接口的对象。那有一个方法(称为actionPerformed());您将代码放入该方法中:

myButton.addActionListener(new ActionListener() {
    public void actionPerformed(ActionEvent e) {
        // Do something
    }
});

当他们添加 lambda 时,他们希望与所有现有代码融为一体,并尽可能少地进行更改,因此他们以完全相同的方式进行操作:编译器推断您正在实现哪个接口,并创建一个实现该接口的对象。你可以写:

myButton.addActionListener(e -> {
    // Do something
});

它更短——但它编译下来与第一个示例几乎相同。

所以在 Java 中,函数不是一等的对象。lambda 只是实现功能接口的一种更简洁的方式。

然而,在 Kotlin 中,函数一等对象:您可以自己编写一个 lambda(或匿名函数)、分配它、将它传递给函数、从函数返回它等等——因此不需要 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 样式的快捷方式,如您的示例所示。

(您可能认为或可能不认为这是一件好事……)


推荐阅读