一、什么是高阶函数?
如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。
Tip:此篇不介绍lambda表达式的用法了,但是看懂确实需要理解这个东西,因为是跟高阶函数配套使用的,所以不会的可以先去搜一搜,看一下
二、开始从简单的高阶函数来试着理解它
新建一个类,用来测试几个函数
class Animal(var type: String, var food: String) {
fun info(): String {
return type + "爱吃" + food
}
}
with
1>源代码
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
- 入参有两个receiver和block,返回值则是block的返回值,T的来源是receiver
- 然后我们看使用
val animal = Animal("兔子", "萝卜")
val result = with(animal) {
type = "老虎"
food = "肉"
info()
}
println(result)
第一步:可以看到with,传了两个参数,一个为animal,一个为大括号的内容(lambda用法)
第二步:看源码中block的类型是T.(),用“使用代码”翻译一下就是animal.方法,所以就可以直接用Animal中的方法,不用it去调用
第三步:block返回的是R,animal.方法,一步步执行就看最后调的方法返回啥就返回啥了,然后整个函数返回R
上面代码返回“老虎爱吃肉”
let
1>源码
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
- 参数只传入一个block,但是block的入参中传了一个T,T从哪里来呢
- 发现let函数前面多了T. 根据前面with的分析,可以知道,T.其实就是代表直接调用T的方法
- 看使用
val result1 = animal?.let {
it.type = "狗"
it.food = "骨头"
it.info()
}
println(result1)
解释上面的意思,就是block函数中将animal实例传了进去,it就代表animal,然后返回的参数依然是函数体运行的最后一行的返回值
run
1>源代码
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
- 他是以上两个的结合
- block的入惨同with一样,所以不用it,可以在匿名函数中直接调用animal的方法
- T的来源是T.run,同let一致,这样写的好处是,可以对animal在调用前整个判空
若能理解,后面的几个就能看会了,表达能力有限,欢迎批评指正