Kotlin延伸lambda与普通lambda

时间:2018-02-01 08:25:19

标签: lambda kotlin extension-methods

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

:data-something="myDataProp"

输出(我关心),如下:

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)
        }
    }
}

问题是为什么这些lambdas可以互换?不应该是不同的东西?编译器是否在幕后做了“聪明”的事情?

1 个答案:

答案 0 :(得分:4)

差异

它并不是完全可以互换的,因为&#34;扩展lambdas&#34;,技术上称为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的实例。带有reiceiver的regular和lambdas都编译成了这样一个对象。因此,如何在Kotlin代码中定义参数predicate并没有什么不同。