为什么 Kotlin 中需要显式函数接口修饰符?

rog*_*one 5 kotlin

考虑用 Java 定义的 SAM

public interface Transform {
   public String apply(String str);
}
Run Code Online (Sandbox Code Playgroud)

该接口自动支持 Kotlin 中的 lambda 到类型转换

fun run(transform: Transform) {
    println(transform.apply("world"))
}

run { x -> "Hello $x!!" } // runs fine without any issues
Run Code Online (Sandbox Code Playgroud)

但现在考虑一个 Kotlin 接口

interface Transform2 {

    fun apply(str: String): String

}
Run Code Online (Sandbox Code Playgroud)

现在调用 run 函数的唯一方法是创建 Transform2 的匿名实例

run(object : Transform2 {
        override fun transform(str: String): String = "hello $str!!"
})
Run Code Online (Sandbox Code Playgroud)

但如果我们将 Transform2 接口设为函数式接口,则以下情况是可能的

run { str -> "hello $str!!" }
Run Code Online (Sandbox Code Playgroud)

为什么 Kotlin 编译器无法自动将 lambda 类型转换为匹配的接口(就像处理 Java 接口一样),而不需要显式地将所述接口标记为函数式接口。

Swe*_*per 10

我在KT-7770的评论中找到了某种理由:

...将所有适用的接口视为 SAM 可能过于意外/隐含:具有 SAM 适用接口的人可能不会假设它将用于 SAM 转换。因此,向接口添加另一个方法变得更加痛苦,因为它可能需要更改调用站点上的语法(例如,将可调用引用转换为对象文字)。

因此,当前的愿景是为接口添加某种修饰符,在应用时:

  • 添加接口是否为有效 SAM 的检查
  • 允许在调用站点上进行 SAM 转换

像这样的东西:

fun interface MyRunnable {
     fun run()
}
Run Code Online (Sandbox Code Playgroud)

基本上,他是说,如果默认情况下隐式完成 SAM 转换,并且我向接口添加一些新方法,则将不再执行 SAM 转换,并且需要更改每个使用转换的地方。“fun”一词的作用是告诉编译器检查该接口确实只有一个抽象方法,同时也告诉调用站点这确实是一个 SAM 接口,他们可以期望作者不会突然添加新的抽象方法方法到接口,突然破坏了他们的代码。

该线程继续讨论为什么相同的论点不能应用于 Java原因本质上可以归结为“Java 不是 Kotlin”。