文章目录
- [1. 概念介绍](#1. 概念介绍)
- [2. 使用方法](#2. 使用方法)
-
- [2.1 函数类型的变量](#2.1 函数类型的变量)
- [2.2 高阶函数](#2.2 高阶函数)
- [3. 内容总结](#3. 内容总结)
- 4.经验分享
我们在上一章回中介绍了Jetpack中Icon和Imamg相关的内容,本章回中主要介绍Kotlin中的 lambda
、匿名函数和闭包。闲话休提,让我们一起Talk Android Jetpack吧!
1. 概念介绍
关于lambda
的概念比较抽象,我们通过它的特征来描述它的概念:由花括号包裹并且有箭头特征的表达式就是lambda,花括号是整个lambda的内容,箭头前的内容是它的参数,箭头后的内容是它的实现内容。
和lambda比较类似是的匿名函数和闭包,匿名函数就是没有函数名的函数,lambda也没有名称,因此它们十分相似,只有在函数有返回值的时候它们才不同:匿名函数有明确的return语句,而lambda表达式没有明确的返回语句,它通常把实现内容中最后一个表达式的值当作返回值。
闭包比较好理解:位于花括号中的内容就是闭包。虽然lambda
也位于花括号内,但是它只是闭包的一部分,闭包中包含的内容不只是lambda,因此可以把lamdba看作是闭包的子集。
明白这些概念后,我们通过具体的代码来演示它的使用方法。
2. 使用方法
2.1 函数类型的变量
kotlin
//变量类型是函数,使用匿名函数来赋值
var funValue:()->String = fun():String{return "this is a function"}
//变量类型是函数,使用lambda来赋值
var funValue0:()->String = {"this is a function"}
//变量类型是函数,使用匿名函数来赋值,省略变量类型
var funValue1 = fun():String { return "this is a function"}
//变量类型是函数,使用lambda赋值,省略变量类型
var funValue11 = {"this is a function"}
//只有一行语句时花括号也可以省略
var funValue111 = "this is a function"
上面的示例代码中,我们定义了变量funValueXXX
(为了区分不同的变量名称在尾部添加了多个数字),它的类型是函数类型,我们先使用匿名函数给它赋值,然后再使用lambda
表达式给它赋值,这样可以区分开匿名函数和lambda表达式的差异。
从代码中可以看到匿名函数的特点:有关键字fun和return.相比之下lambda就可以省略这些关键字,甚至连大括号也可以省略。接下来我再演示一个复杂一些函数类型。
kotlin
//变量类型是函数,函数有参数,但是无返回值,使用匿名函数来赋值,这做做法也叫类型实例化
var funValue2:(values:Int)->Unit =fun (values:Int){ "this is a function,param:$values"}
//变量类型是函数,函数有参数,但是无返回值,使用匿lambda来赋值,这做做法也叫类型实例化
var funValue21:(values:Int)->Unit ={values -> "this is a function,param:$values"}
//变量类型是函数,函数有参数和返回值,使用匿名函数来赋值
var funValue31:(values:Int)->String = fun(values):String {return "this is a function,param:$values"}
//变量类型是函数,函数有参数和返回值,使用lambda来赋值
var funValue32:(values:Int)->String ={values -> "this is a function,param:$values"}
//变量类型是函数,使用lambda来赋值,省略了参数,只有一个参数时使用it代替参数,it是单个参数的隐式名称
var funValue33:(values:Int)->String ={ "this is a function,param:$it"}
上面的示例代码中,我们定义了变量funValueXXX
(为了区分不同的变量名称在尾部添加了多个数字),它的类型是函数类型,这个函数带有参数,而且分有返回值和无返回值的两种情况。我们先使用匿名函数给它赋值,然后再使用lambda
表达式给它赋值,这样可以区分开匿名函数和lambda表达式的差异。
从代码中可以看到当函数类型中包含返回值时匿名函数的内容比lambda
多,lambda显得相对简洁一些。当函数类型中带有参数时lambda表达式显得更加简洁。
看了这么多示例,可以得出lambda
表达式最大的特征就是有箭头。此外,lambda表达式还有一个语法就是省略参数,使用it来代替参数。这个语法在compose中经常使用。
2.2 高阶函数
高阶函数就是函数的参数或者返回值的类型是其它函数,相当于把函数当作变量传递给高阶函数的参数或者当作高阶函数的返回值。下面是我们通过示例代码来演示:
kotlin
//高阶函数:函数的参数或者返回值是其它的函数,相当把函数当作数值来使用
fun inFun(name:String,age: Int):String {
return name+age
}
//只有一行语句时可以省略大括号和return
fun inFun1(name:String,age: Int):String = name+age
//返回类型可以通过类型推导出来,也可以省略
fun inFun2(name:String,age: Int) = name+age
//函数的第二个参数是函数类型
fun outFun(id:Int,type:(s:String,a:Int)->String):String {
val age = (1..10).random()
println(inFun("Sam ",age))
println("id: $id, type: $type")
return "age = $age"
}
//通过函数引用把命名函数(具名函数)inFun1当作参数传递给outFun函数
var res = outFun(3, ::inFun1)
//把匿名函数当作参数传递给outFun函数,注意关键字fun不能省略
var res1 = outFun(33,fun(s:String,a:Int):String{return "str = $s ,$a"})
//使用lambda表达式代替匿名函数,把lambda表达式传递给outFun函数
//注意lambda必须使用花括号包起来,箭头前是参数,箭头后是函数体
//注意匿名函数的return不能省略,lambda的可以省略,而且通常是最后一个表达式的值
var res2= outFun(33,{s:String,a:Int->"str = $s ,$a"})
//省略lambda表达式中的参数类型,返回类型,return关键字
var res3= outFun(33,{s,a->"str = $s ,$a"})
//函数的最后一参数是lambda时可以将其移动到括号外面(这叫尾lambda)
var res4= outFun(33){s,a->"str = $s ,$a"}
上面的示例代码中包含高阶函数,该函数的参数是函数类型,从示例代码中可以看到使用lambda
表达式传递参数比匿名函数传递参数的代码要简洁一些。代码中介绍了函数的两种语法:
- 通过等号来实现简单函数体,进而省花括号和return关键字;
- 通过函数引用(两个冒号)来传递命名函数给高阶函数;
代码中还介绍一种尾lambda
的语法:当lambda是高阶函数的最后一个参数时,可以将它移动到高阶函数的外面,也就是花括号中。这个语法在compose中十分常见。
3. 内容总结
最后,我们对本章回中的内容做一个总结:
- lambda和匿名函数十分类似,它们都可以用来给函数类型的变量赋值,或者和高阶函数一起使用;
- 与lambda表达式类似还有闭包,它的范围比较广,lambda只是它的一个子集;
- 匿名函数的特征就是没有函数名,但是有fun和return关键字;
- lambda表达式的特征就是有箭头和花括号;
- 在大部分场景下lambda的语法更加简洁;
4.经验分享
关于lambda
表达式和匿名函数的语法,大家普通的反应就是看不懂代码。这就是代码简洁与代码易懂之间的茅盾,我在开始看这类代码时也有同样的感觉,我的经验就是:尽量让代码保持简洁,如果感觉读不懂代码,那么多动手练习一下就可以掌握这种难理解的语法。比如,上面的示例代码都是我自己对匿名函数和lambda表达式的理解,多写一些就会明白其中的原理,到时候就能读懂代码了。
此外,还有一些特殊的语法,只能是硬记语法规则,这个没有任何窍门,好在特殊内容比较少,比如前面小节中介绍的尾lambda和it。
我最开始看这类代码是在Java中,还记得给Button添加监听器(setOnClickListener
)就是使用匿名函数,刚开始不理解,但是写多了就养成了习惯,反而觉得这种写法十分方便。我把这个学习经验从Java迁移到了Kotlin中,在此分享给大家,希望对大家有帮助。
看官们,关于Kotlin中的lambda、匿名函数和闭包就介绍到这里,欢迎大家在评论区交流与讨论!