从with、let、run、apply等理解高阶函数

2023-10-31  本文已影响0人  蓝库知识

一、什么是高阶函数?

如果一个函数接收另一个函数作为参数,或者返回值的类型是另一个函数,那么该函数就称为高阶函数。

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()
}
  1. 入参有两个receiver和block,返回值则是block的返回值,T的来源是receiver
  2. 然后我们看使用
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)
}
  1. 参数只传入一个block,但是block的入参中传了一个T,T从哪里来呢
  2. 发现let函数前面多了T. 根据前面with的分析,可以知道,T.其实就是代表直接调用T的方法
  3. 看使用
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()
}
  1. 他是以上两个的结合
  2. block的入惨同with一样,所以不用it,可以在匿名函数中直接调用animal的方法
  3. T的来源是T.run,同let一致,这样写的好处是,可以对animal在调用前整个判空

若能理解,后面的几个就能看会了,表达能力有限,欢迎批评指正

上一篇 下一篇

猜你喜欢

热点阅读