Kotlin 函数类型核心笔记:Lambda、闭包、函数引用入门到实践
目录
什么是匿名函数
定义时不取名字的函数,称之为匿名函数,匿名函数通常整体传递给其他函数,或者从其他函数返回。
匿名函数对Kotlin来说很重要,有了它,我们能够根据需要制定特殊规则,轻松定制标准库里的内置函数。
fun main(){
val total = "Mississippi".count()
val totals = "Mississippi".count({letter->
letter == 's'
})
println(total)
println(totals)
}

使用匿名函数给标准函数指定规则
{letter->
letter == 's'
}
函数类型与隐式返回
匿名函数也有类型,匿名函数可以当作变量赋值给函数类型变量,就像其他变量一样,匿名函数就可以在代码里传递了。变量有类型,变量可以等于函数,函数也会有类型。函数的类型,由传入的参数和返回值类型决定。
和剧名函数不一样,出来极少数情况外,匿名函数不需要 return 关键字来返回数据,匿名函数会隐式或自动返回函数体最后一行语句的结果。
//变量的类型是一个匿名函数
val blessingFunction:()-> String //无参,返回String
blessingFunction = {
val holiday = "New Holiday"
"Happy $holiday"
}
println(blessingFunction())
![]()
blessFunction这个变量是一个匿名函数,无参,返回值是String。
匿名函数无需return。
那如果我在匿名函数内部写两个返回的String呢?
//变量的类型是一个匿名函数
val blessingFunction:()-> String //无参,返回String
blessingFunction = {
val holiday = "New Holiday"
"Happy $holiday"
"Happy"
}
println(blessingFunction())
此时,匿名函数内部两个String,编辑器自动将 "Happy $holiday" 变灰,表示无效。
![]()
运行结果为Happy,因此如果有多个返回值,不会报错,返回最后一个返回值。
函数参数
匿名函数可以不带参数,也可以带一个或者多个任何类型的参数,需要带参数是,参数的类型放在匿名函数的类型定义中,参数名放在函数定义中。
val blessingFunction:(String) -> String = {name ->
val holiday = "New Year."
"$name ,Happy $holiday"
}
println(blessingFunction("Jack"))
![]()
it关键字
定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。两个值参就不能用了。
val blessingFunction:(String) -> String = {it ->
val holiday = "New Year."
"$it ,Happy $holiday"
}
println(blessingFunction("Jack"))
将上面的name改为it,运行结果一致。
![]()
类型推断
省去返回值参数,以无参数举例:
val blessingFunction = {
val holiday = "New Year."
"Happy $holiday"
}
println(blessingFunction())
![]()
类型推断也支持带参数的匿名函数,但为了帮助编译器更准确地推断变量类型,匿名函数的参数名和参数类型必须有。
val blessingFunction = {name:String, year:Int ->
val holiday = "New Year,"
"$name,Happy $holiday $year"
}
println(blessingFunction("Jack",2027))
![]()
lambda
匿名函数称为lambda,定义称为lambda表达式,返回的数据称为lambda结果。
定义参数是函数的函数
函数的参数是另外一个函数(无限套娃)
fun main(){
val getDiscountWords = {goodsName:String,hour: Int->
val currentYear = 2017
"$currentYear year,11.11 $goodsName discount last:$hour hours"
}
showOnBoard("papers",getDiscountWords)
}
fun showOnBoard(goodsName:String,getDiscountWords:(String,Int)->String){
val hour = (1..24).shuffled().last()
println(getDiscountWords(goodsName,hour))
}
此处,我理解匿名函数可以理解为一个具有函数体和参数的变量,使用时当作变量用,定义时当作函数定义。
简略写法
如果一个函数地lambda参数排在最后,或者是唯一的参数,那么括住lambda值参地一对圆括号就可以省略。
lambda是唯一的参数:
val totals1 = "Mississippi".count({letter->
letter == 's'
})
val totals2 = "Mississippi".count{it->
it == 's'
}
totals1和totals2等价。
感觉写法很多,还是很花里胡哨的,具体看编辑器提示应该就可以。
看到一个很有意思的弹幕:学的时候很离谱,用的时候很快乐。
用法太多,我想是到时候记不清了,随便写也能写对其中的一种吧。
lambda参数排在最后:
//fun main(){
// val getDiscountWords = {goodsName:String,hour: Int->
// val currentYear = 2017
// "$currentYear year,11.11 $goodsName discount last:$hour hours"
// }
//
// showOnBoard("papers",getDiscountWords)
//}
//
//
//fun showOnBoard(goodsName:String,getDiscountWords:(String,Int)->String){
// val hour = (1..24).shuffled().last()
// println(getDiscountWords(goodsName,hour))
//}
fun main(){
showOnBoard("papers"){goodsName:String,hour: Int->
val currentYear = 2017
"$currentYear year,11.11 $goodsName discount last:$hour hours"
}
}
fun showOnBoard(goodsName:String,getDiscountWords:(String,Int)->String){
val hour = (1..24).shuffled().last()
println(getDiscountWords(goodsName,hour))
}
上面注释的可以精简为下面,主要是将getDiscountWords这个匿名函数直接写到showOnBoard里面。
函数内联
lambda可以更灵活地编写应用,但是,灵活是需要付出代价地。
在JVM上,定义的lambda会以对象实例的形式存在,JVM会为所有同lambda打交道的变量分配内存,这就产生了内存开销。更糟的是,lambda的内存开销会带来严重的性能问题。
幸运的是,Kotlin有一种优化机制叫内联,JVM就不需要使用lambda对象实例了,因而避免了变量内存分配。哪里需要使用lambda,编译器就会将函数体赋值粘贴到哪里。
使用lambda的递归函数无法内联,因为会导致复制粘贴无限循环,编译会发出警告。
函数引用
要把函数作为参数传给其他函数使用,除了传lambda表达式,Kotlin还提供了其他方法,传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambda表达式的地方,都可以使用函数引用。
fun main(){
showOnBoard("papers",::getDiscountWords)
}
//具名函数
private fun getDiscountWords(goodsName:String,hour: Int):String {
val currentYear = 2017
return "$currentYear year,11.11 $goodsName discount last:$hour hours"
}
private fun showOnBoard(goodsName:String,getDiscountWords:(String,Int)->String){
val hour = (1..24).shuffled().last()
println(getDiscountWords(goodsName,hour))
}
::函数名,完成函数引用,将一个函数传入另一个函数的参数里。
函数类型作为返回类型
晕.......
函数类型也是有效的返回类型,也就是说可以定义一个能返回函数的函数。
fun main(){
val getDiscountWords = configDiscountWords()//getDiscountWords是一个函数,需要传参goodsName:String
getDiscountWords("Papers")//传参
}
fun configDiscountWords():(String)->String{
return {goodsName:String->
val currentYear = 2017
val hour = (1..24).shuffled().last()
"$currentYear year,11.11 $goodsName discount last:$hour hours"
}
}
闭包
- 在Kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量,Kotlin中的lambda就是闭包。
fun main(){
val getDiscountWords = configDiscountWords()//getDiscountWords是一个函数,需要传参goodsName:String
println(getDiscountWords("Papers"))//传参
}
fun configDiscountWords():(String)->String{
val currentYear = 2017
val hour = (1..24).shuffled().last()
return {goodsName:String->
"$currentYear year,11.11 $goodsName discount last:$hour hours"
}
}
因此返回一个函数时,可以将一些变量定义在configDiscountWords里面,不影响匿名函数引用着定义自身的函数里的变量
- 能接收函数或者返回函数的函数又叫做高级函数,高级函数广泛应用与函数式编程当中。
lambda与匿名内部类
为什么要在代码中使用函数类型?少写模块化代码,写出更灵活的代码。Java8支持面向对象编程和lambda表达式,但不支持将函数作为参数传给另一个函数或变量,不过java的替代方案是匿名内部类。
更多推荐
所有评论(0)