Kotlin 扩展 lambda 与常规 lambda
Kotlin extension lambdas vs regular lambdas
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。
fun main(args: Array<String>) {
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<Int>, 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 可以互换?不应该有什么不同吗?编译器是否在幕后做了一些事情 "smart"?
差异
它不能完全互换,因为 "extension lambdas",技术上称为 ,可以在接收器上调用,这对于常规 lambda 是不可能的:
predicateWithReceiver(2) //OK
2.predicateWithReceiver() //OK
regularPredicate(2) //OK
2.regularPredicate //Not OK
带有接收者的 Lambda 可以作为带有参数的普通函数调用,但也可以直接在其接收者对象上调用(类似于扩展)。更重要的部分是这样的 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);
}
}
}
过滤器函数采用 Function1
的实例。 regular 和 lambdas with receiver 都被编译成这样的对象。因此,在 Kotlin 代码中如何定义参数 predicate
并没有什么不同。
根据以下源代码,常规 lambda 似乎可以与扩展 lambda 互换。
fun main(args: Array<String>) {
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<Int>, 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 可以互换?不应该有什么不同吗?编译器是否在幕后做了一些事情 "smart"?
差异
它不能完全互换,因为 "extension lambdas",技术上称为
predicateWithReceiver(2) //OK
2.predicateWithReceiver() //OK
regularPredicate(2) //OK
2.regularPredicate //Not OK
带有接收者的 Lambda 可以作为带有参数的普通函数调用,但也可以直接在其接收者对象上调用(类似于扩展)。更重要的部分是这样的 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);
}
}
}
过滤器函数采用 Function1
的实例。 regular 和 lambdas with receiver 都被编译成这样的对象。因此,在 Kotlin 代码中如何定义参数 predicate
并没有什么不同。