考虑用Java定义的SAM
public interface Transform {
public String apply(String str);
}此接口支持lambda自动在Kotlin中进行类型转换。
fun run(transform: Transform) {
println(transform.apply("world"))
}
run { x -> "Hello $x!!" } // runs fine without any issues但是现在考虑一下Kotlin接口
interface Transform2 {
fun apply(str: String): String
}现在调用run函数的唯一方法是创建一个匿名Transform2实例。
run(object : Transform2 {
override fun transform(str: String): String = "hello $str!!"
})但是,如果我们将Transform2接口作为一个功能接口,那么下面的内容是可能的
run { str -> "hello $str!!" }为什么Kotlin编译器不需要显式地将这些接口标记为一个功能接口,就不能自动将强制转换的lambda键入到匹配的接口(就像它对Java接口所做的那样)。
发布于 2022-01-03 18:14:15
..。将所有可应用的接口视为SAM可能太出乎意料/隐含:一个具有SAM可应用接口的接口可能不会假设它将用于SAM转换。因此,向接口添加另一个方法会变得更加痛苦,因为它可能需要更改调用站点上的语法(例如,将可调用引用转换为对象文本)。 正因为如此,当前的设想是在应用时为接口添加某种修饰符:
就像这样:
有趣的接口MyRunnable {趣味运行()}
基本上,他是说,如果SAM转换是默认情况下隐式完成的,而且我在接口中添加了一些新方法,那么SAM转换将不再被执行,使用转换的每个地方都需要更改。“乐趣”一词是为了告诉编译器检查接口确实只有一个抽象方法,并告诉调用站点这确实是一个SAM接口,他们可以期望作者不会突然向接口添加新的抽象方法,从而突然中断他们的代码。
线程继续讨论为什么不能将相同的参数应用于Java,原因本质上归结为"Java“。
发布于 2022-01-03 19:13:32
这是猜测,但我强烈怀疑其中一个原因是避免在Kotlin的更自然的方法之上鼓励使用功能接口。
函数接口是Java解决向Java语言中添加lambda的问题的解决方案,这种方式涉及到最近的更改和风险,以及与Java在没有这些接口的近20年中的最佳实践的最大兼容性:使用实现命名接口的匿名类。 需要无数不同的命名接口,如Supplier、BiFunction、DoublePredicate…。每个接口都有各自的方法和参数名称,每个接口都与所有其他接口不兼容--以及与多年来人们开发的所有其他接口不兼容。-但它们都是不相关和不兼容的。) 和所有这些都是为了弥补Java没有一流函数这一事实。
Kotlin 有 一级函数,它是一种更通用、更优雅、更强大的方法--. (例如,您可以使用单个参数编写lambda (或函数或函数文字),并在需要接受单个参数的函数的任何地方使用它,而不必担心它的确切接口。 无需在类似的界面之间进行选择。或者写你自己的,如果没有的话。当 不能推断正确的接口类型时,就不会出现任何隐藏的问题。) 所有的标准库都使用函数类型,就像大多数其他Kotlin代码编写的那样。 并且因为它们被广泛使用,它们得到了广泛的支持:作为Kotlin生态系统的一部分,每个人都受益。
因此,Kotlin支持函数接口,主要是为了与Java. Compared兼容,与一流的函数兼容,它们基本上是一个黑客。 是一个非常巧妙而优雅的黑客,考虑到向后兼容性对Java平台有多么重要,可以说是必要的。但无论如何, 和我怀疑JetBrains希望鼓励人们在可能的情况下优先使用函数类型。
在Kotlin中,您必须显式地请求一些特性,这些特性可以提高Java兼容性,但可能导致更糟的Kotlin代码(例如静态方法的@JvmStatic,或者转换到java.lang.Object以调用notify())--它符合与您还必须显式请求函数接口(通过使用fun interface)的相同模式。
(还请参阅我关于这一主题的先前的回答。)
https://stackoverflow.com/questions/70569535
复制相似问题