lambda - Kotlin 扩展 lambda 与常规 lambda

标签 lambda kotlin extension-methods

根据以下源代码,常规 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 表达式可以互换?不应该有什么不同吗?编译器在幕后做着“聪明”的事情吗?

最佳答案

差异

它不能完全互换,因为“扩展 lambdas”,技术上称为 lambdas with receiver , 可以在接收器上调用,这对于常规 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 的实例.带有接收器的常规和 lambda 表达式都被编译成这样一个对象。因此,定义参数 predicate 的方式没有区别。在您的 Kotlin 代码中。

关于lambda - Kotlin 扩展 lambda 与常规 lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48558252/

相关文章:

flutter - Dart扩展功能仅在与调用它的文件相同时可见

c++ - && 对 lambda 表达式有什么好处?

java - 如何在 Java 中迭代 lambda 函数

android - Volley StringRequest 响应更改撇号的值(' 更改为 â)

intellij-idea - IntelliJ/Kotlin : What does the `^use` hint mean?

android - 如何延迟 RxJava 2 和 Android 中的 onError()?

c# - 自动映射器的通用扩展方法

C# lambda 表达式,作用域变量值

generics - 从 lambda 参数推导时,Kotlin 泛型失败

c# - C# 有扩展属性吗?