Ktolin——高阶函数与lambda表达式

一、前言

在Ktolin语言的学习中,高阶函数与lambda表达式尤为重要。想要学好Ktolin,就得啃下这块硬骨头,下面就让我们一起来理理Kotlin的高阶函数与lambda表达式吧!


二、高阶函数

在Kotlin语法中,函数可以作为参数、变量等去实现参数变量都能实现的操作,如下解释:

Kotlin 函数都是头等的,这意味着它们可以存储在变量与数据结构中,并可以作为参数传给其他高阶函数以及从其他高阶函数返回。可以像操作任何其他非函数值一样对函数进行操作。

而高阶函数就是实现了让函数作为参数进行传递,解释如下:

高阶函数——高阶函数是将函数用作参数或返回值的函数。


三、lambda表达式

基于高阶函数的特点,kotlin编译了一套独特的函数类型来实现对函数的调用,即lambda表达式。lambda表达式不仅让函数的调用更加方便,也让开发更加简洁,代码也看起来清爽了不少,下面就让我们一同来理理lambda表达式相关的知识点呐~

1.首先我们要先了解“it”与“this”

在高阶函数中,对相应类进行扩展,在扩展的函数中将另一个函数作为自己的参数调用,实现数据、方法等的回调。在使用到的变量函数中就涉及到是否有参、以及其本身是否又是一个新的扩展函数问题。示例如下:

//所有的高阶函数都必须使用inline修饰,避免不必要的创建对象,inline让编译时只是做了一个替换引用的效果
inline fun String.show1(lambda:(String)->Unit){
    lambda(this)
}//变量函数有参,对应以下第一种

inline fun String.show2(lambda:String.()->Unit){
    this.lambda()
}//变量函数又作为一个扩展函数,对应以下第二种

第一种,变量函数有参类型:
高阶函数中,变量函数有参,实现的就是将自己本身作为参数运用到变量函数中实现数据、事件等一些类的回调。

当参数有且只有一个时,在函数在实现中就会创建一个“it”指针,而指针指向的就是参数(回调对象)本身。示例如下:

"jake".show1 {  //it:String
        println("hello $it")
    }.apply {  }

当参数有且不只有一个时,就需要指定好每个参数所对应的名称,示例如下:

inline fun String.show1(lambda:(name:String,age:Int)->Unit){
    lambda("",6)
}

"jake".show1 {name,age->
        println("hello $name$age")
    }.apply {  }

第二种,变量函数又作为一个扩展函数类型:
高阶函数中变量函数又作为一个扩展函数,即实现了对 当前调用这个函数的对象的调用,即是创建了“this”指针,指向当前调用对象,从而实现对象的回调,以及对其进行一系列的操作,示例如下:

"Merry".show2 {//this:String
        println("hello $this")
    }.apply {  }

关于该点的“it”与“this”总结下来就两句话!

什么时候有it:lambda中参数只有一个
什么时候有this:lambda是某个类型的扩展函数

2.了解lambda基本模板

lambda既然是Kotlin中一种通用的函数调用模板,即任意函数都可以调用,因此lambda就作为的是泛型的扩展函数,实现任意类型都可调用。

根据一个lambda有参,一个lambda作为某个类的扩展函数,基本模板如下:

//it
fun <T> T.show03(lambda: (T) -> Unit){
    lambda(this)
}
//this
fun <T> T.show04(lambda: T.() -> Unit){
    this.lambda()
}

( 2.over~)

3.lambda之kotlin语法糖——apply also with run use takeif

(1)apply
使用情景:当对象调用函数时只需要进行简单的初始化以及调用函数内的方法

重写源码:

inline fun <T> T.myApply(lambda:T.()->Unit):T{
    this.lambda()
    return this
}

解释:对于没有进行额外操作,只是对调用函数的属性以及方法进行初始化和调用,所以apply中的lambda是无参且作为一个泛型的扩展函数。
无参->无需做额外操作
扩展->this指针指向当前所调用的对象。

(2)also
使用情景:当前调用对象除了对函数进行初始化以及其成员函数的调用外,还要进行额外的操作,即操作自己重写。

重写源码:

inline fun <T> T.myAlso(lambda: (T) -> Unit):T{
    lambda(this)
    return this
}

解释:基于被调用的函数的基本实现外,还要进行额外的操作,故also中的lambda为有参类型的
有参->需要参数对应做额外操作

(3)with
使用情景:除了对调用函数的基本实现外,还需要有返回值,且返回值为任意类型(代码最后一行)

重写代码:

inline fun <T,R> myWith(value:T,lambda: T.() -> R):R{
    return value.lambda()
}

解释:当对象调用函数时还需要对其返回一个值,故with里的lambda有两个参数且有一个T泛型返回值
两个参数->第一个为value即代表当前调用这个函数的对象本身,第二个R作为高阶函数返回值

(4)run
使用情景:故名思意,run为跑一段代码,就是开始执行一段代码

重写源码:

inline fun <R> myRun(lambda: () -> R) :R{
    return lambda()
}

解释:作为基本的执行一段代码,故run中的lambda即无参也不作为一个扩展函数,但有返回值R

(5)use
使用情景:它能保证Lambda表达式中的代码全部执行完之后自动将外层的流关闭,这样我们就不需要再写一个finally语句,手动关闭流了。

(6)takeif
使用情景:在给定条件下判断是否返回调用这个对象本身,通过lambda里的代码块执行结果来判断

重写源码:

inline fun <T> T.myTakeif(lambda: (T) -> Boolean):T?{
    return if (lambda(this)) this else null
}

解释:通过lambda里代码块的执行结果来判断是否返回这个对象,即lambda里为有参且返回值为Boolean类型,高阶函数是否返回为未知
有参->需要把当前调用函数的对象来进行一段代码块的操作
lambda返回Boolean值->返回代码块执行结果
高阶返回未知->根据lambda结果判定是否返回

(takeuless使用情景与takeif相似,但返回判定相反~)


四、小结

从浅到深,从了解到会用,中间或许就只差静下心来几十分钟的探索。

Kotlin高阶函数在书写到运用上都十分简明易上手,相较于Java也省去了许多不必要对象的创建,节省了内存还大大提高了代码的运行速度,给我们的开发带来了大大的便利。

学好他,加以灵活运用,枯燥的代码也会生花。路漫漫其修远兮,我们一同加油!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。