高阶函数和Lambda表达式
高阶函数是接受函数作为参数或者将函数作为返回值的函数。我们可以将C语言中使用回调函数的函数称为高阶函数。
例如我们有一个数值处理函数processNum()
,对于给定Int型数据,依次执行两个处理过程 proc1 和 proc2 :
fun processNum(num: Int, proc1: (Int) -> Int, proc2 (Int) -> Int): Int {
return proce2(proc1(num))
}
如上,processNum()
是高阶函数,它包含函数类型参数proc1
和proc2
。
高阶函数需要函数作为参数,这就要求调用时需要一个函数实参。如果在其他地方声明函数并在高阶函数调用处传入非常不利于代码阅读的连贯性(各种代码跳转很难阅读),并且有时函数的实现逻辑非常的简单,重新声明一个函数的大部分代码都是模板代码。这时Lambda表达式就有用了。
可以将Lambda理解为“字面值函数”。试想,如果在调用一个函数时我们已经知道了一个 Int 实参就是字面值 1 ,那么我们就可以直接使用1作为参数调用这个函数而不需要声明一个Int变量将它赋值为 1 然后再作为实参去调用函数! 使用Lambda表达式的思路与此类似:如果我们已经知道了这个函数参数的“样子”我们就可以直接用Lambda表达式表示出来作为实参,而不需要再声明一个函数并将函数作为实参!
it 语法糖
如果Lambda表达式只有一个参数那么可以省略该参数和 ->
并可以在Lambda表达式中使用 it
来代替该参数。在Lambda的唯一参数被省略时,it
用来代表该参数!
Lambda 表达式和闭包
Lambda表达式能够访问其闭包中的变量,不同于Java,Kotlin还可以修改这些变量。如果 this
在闭包中有定义,那么在Lambda表达式中也可以使用this。
Lambda表达式中的 this
需要特别注意,如果为Lambda表达式指定了 receiver 那么在Lambda表达式中 this
代表它的 receiver,否则 this
与其闭包中的 this
等价。 如果需要访问Lambda表达式闭包中的变量,而这个变量名和其receiver中的变量名冲突,此时需要 this@<closureName>.<varNmae>
语法来指明该变量是Lambda表达式闭包中的变量。如果情况复杂分不清 this
指向谁,那么总是使用 this@
是不容易出错的做法!
Kotlin 标准库中的高阶函数
run 函数
不带 receiver 的 run
函数执行参数中的可执行对象,将返回值作为 run
的返回值:
/**
* Calls the specified function [block] and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <R> run(block: () -> R): R = block()
带 receiver 的 run
将上下文中的 this
指向 receiver 并执行参数中的可执行对象,将返回值作为 run
的返回值:
/**
* Calls the specified function [block] with `this` value as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R = block()
with 函数
换了个写法的带 receiver 的 run
函数:
/**
* Calls the specified function [block] with the given [receiver] as its receiver and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R = receiver.block()
apply 函数
类似带 receiver 的 run
函数,可执行对象参数的执行上下文中 this
被设置为receiver。不同的是apply返回 receiver 本身。
/**
* Calls the specified function [block] with `this` value as its receiver and returns `this` value.
*/
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T { block(); return this }
apply
函数将处理过程“应用”到 receiver 上并返回 receiver 本身,这适用于修改 receiver 的场景,比如将某个函数的返回值修正一下。
let 函数
let
函数将 receiver 作为其可执行对象参数的实参传入并执行可执行对象,返回值是可执行对象的返回值:
/**
* Calls the specified function [block] with `this` value as its argument and returns its result.
*/
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R = block(this)
结合 it语法糖。一般来说在写传入 let
函数的Lambda表达式参数时往往使用 it
表示 let
的 receiver 。
also 函数
它和 let
函数的关系类似于 apply
和带 receiver的 run
函数的关系。also
函数将 receiver 作为其可执行参数的实参传入并执行可执行对象,但是其返回值为 receiver 本身
/**
* Calls the specified function [block] with `this` value as its argument and returns `this` value.
*/
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T { block(this); return this }
如何选择?
:)