目录

什么是匿名函数

函数类型与隐式返回

函数参数

it关键字

类型推断

lambda

定义参数是函数的函数

简略写法

函数内联

函数引用

函数类型作为返回类型

闭包

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的替代方案是匿名内部类。

更多推荐