Kotlin扩展lambdas与常规lambda

根据以下源代码,似乎正常的lambda可以与扩展lambdas互换。

fun main(args: Array) { val numbers = listOf(1, 2, 3) filter(numbers, predicate) filter(numbers, otherPredicate) println("PREDICATE: ${predicate} " + "\nOTHERPREDICATE: ${otherPredicate} " + "\nEQUALITY: ${predicate==otherPredicate}") } val predicate : Int.() -> Boolean = {this % 2 != 0} val otherPredicate : (Int) -> Boolean = {it % 2 != 0} fun filter(list: List, predicate:(Int) -> Boolean) { for(number in list){ if(predicate(number)){ println(number) } } } 

输出(我关心)如下:

 PREDICATE: kotlin.Int.() -> kotlin.Boolean OTHERPREDICATE: (kotlin.Int) -> kotlin.Boolean EQUALITY: false 

问题是为什么这些lambda可以互换? 不应该是不同的东西? 编译器是在做什么“智能”的引擎盖下?

差异

这不是完全可以互换的,因为可以在接收器上调用“extension lambdas”(技术上称为带接收器的lambdas) ,这对于常规lambda来说是不可能的:

 predicateWithReceiver(2) //OK 2.predicateWithReceiver() //OK regularPredicate(2) //OK 2.regularPredicate //Not OK 

带有接收器的Lambdas可以作为具有参数的普通函数被调用,但是也可以直接调用它们的接收器对象(类似于扩展)。 更重要的部分是这样的lambda在调用者站点上的样子,也就是说你不需要使用限定符来访问这个lambda中的可见接收者。

汇编

这是由编译器技术启用的。 以下演示了2.regularPredicate如何在字节码级别上显示(显示为反编译的Java):

  Function1 predicateWithReceiver = ...; predicateWithReceiver.invoke(2); 

它看起来像一个常规的函数调用,翻译由编译器负责。

编辑

至于filter这样的高阶函数,其实并没有什么区别。 看看它是如何编译的(再次描述为Java):

 public static final void filter(@NotNull List list, @NotNull Function1 predicate) { //... if ((Boolean)predicate.invoke(number)) { System.out.println(number); } } } 

filter函数采用Function1一个实例。 与reiceiver的正则和lambdas都编译到这样一个对象。 因此,如何在Kotlin代码中定义参数predicate并没有什么不同。