一套搞定Kotliln (学习笔记二)

目录

匿名函数:

匿名函数类型与隐式返回:

函数参数:

it关键字:

匿名函数的类型推断:

lambda:

lamda的简略:

函数内联:

函数引用:

函数类型作为返回类型:

闭包:

lambda与匿名内部类:


匿名函数:

  • 定义时不取名的函数,我们称之为匿名函数通常整体传递给其他函数,或者从其他函数返回
  • 匿名函数对Kotlin来说很重要,有了它,我们可以轻松的给标准库里的内函数定制特殊规则
fun main(){
    val total:Int = "Mississippi".count({letter -> letter =='s' })
    println(total)
}

匿名函数类型与隐式返回:

        匿名函数也有类型,匿名函数可以当作变量赋值给函数类型变量,就像其他变量一样,匿名函数就可以在代码里传递了。变量有类型,变量可以等于函数,函数也有类型的。函数的类型,由传入的参数和返回值类型决定。

        和具名函数不一样,处了极少数情况外,匿名函数不需要return关键字来返回数据,匿名函数会隐式或自动返回函数体的最后一行语句的结果

fun main(){
    //变量的类型时一个匿名函数
    val blessingFunction:()->String
    blessingFunction = {
        val holiday = "New Year."
        "Heppy $holiday"}
    //执行匿名函数时不是只写变量名还要在变量名后加个()如果有参数就在括号里传参
     println(blessingFunction())

}

函数参数:

        和剧名函数一样,具名函数可以不带参数,也可以带一个或多个任何类型的参数,需要带参数时,参数的类型放在匿名函数的类型定义中,参数名则放在函数定义中

fun main(){
    //变量的类型时一个匿名函数
    val blessingFunction:(String)->String = {name ->    //name是随便起的一个变量名类型可以省略,因为lanbada表达式会用到
        val holiday = "New Year"
        "$name, Happy $holiday"
    }

    println(blessingFunction("Jack"))
  }

it关键字:

        定义只有一个参数的匿名函数时,可以使用it关键字来表示参数名。当你需要传入两个值参,it关键字就不能用了。


匿名函数的类型推断:

和下面代码时一样的

类型推断也支持带参数的匿名函数,但为了帮助编译器更准确地推断变量类型,匿名函数的参数名和参数类型必须有

等于下面这个


lambda:

        我们将匿名函数称为lambda,把它的定义称为lambda表达式,它返回的数据称为lambda结果。为什么叫lambda? lambda也可以用希腊字符入表示,是lambda演算的简称, lambda演算是一套数理演算逻辑,由数学家Alonzo Church (阿隆佐丘齐)于20世纪30年代发明,在定义匿名函数时,使用了lambda演算记法。

定义函数的参数是另外一个函数:

fun main(){
    val getDiscountWords = {goodsName:String, hour:Int ->
        val currentYear = 2017
        //这个匿名函数最终返回的字符串
        "${currentYear}年, 双11${goodsName}促销倒计时: $hour 小时"
    }
    
    showOnBoard("沐浴露", getDiscountWords )

}
//定义个函数,其中一个入参是一个匿名函数
fun showOnBoard(goodsName:String,getDiscountWords: (String ,Int)-> String){
    val hour: Int = (1..24).shuffled().last()
    println(getDiscountWords(goodsName,hour))

}

lamda的简略:

         下面解释这玩意,Lambda是一小段可以作为参数传递的代码。正常情况,参数传递的是变量,现在确实一小段代码。其语法结构如下:

{参数名1:参数类型,参数名2:参数类型->函数体}
  •    1.因此刚才的问题按照语法结构进行套用:
val lambda = { fruit: String -> fruit.length }
val maxLengthFruit = list.maxBy (lambda )
  •   2.首先开始简化,不需要专门定义lambda变量,直接传入。
val maxLengthFruit = list.maxBy ({ fruit: String -> fruit.length } )
  •    3.其次Kotlin规定,一个函数的lambda参数排在最后可移到函数括号的外面,如果Lambda          参数是函数唯一参数的话,可以将括号省略。
//lambda参数是唯一参数情况时
val maxLengthFruit = list.maxBy { fruit: String -> fruit.length }
  •    4.lambda参数不是唯一参数但是是最后一位参数情况时
fun main(){
    showOnBoard("沐浴露" ){goodsName:String, hour:Int ->
        val currentYear = 2017
        //这个匿名函数最终返回的字符串
        "${currentYear}年, 双11${goodsName}促销倒计时: $hour 小时"
    }
}
//定义个函数,其中一个入参是一个匿名函数
fun showOnBoard(goodsName:String,getDiscountWords: (String ,Int)-> String){
    val hour: Int = (1..24).shuffled().last()
    println(getDiscountWords(goodsName,hour))
}
  •   5.根据类型推导机制,参数列表不必声明参数类型,因为可以推导。
val maxLengthFruit = list.maxBy { fruit -> fruit.length }
  •   6.最后,当参数列表只有一个参数时,不必声明参数名,而是使用it关键字替代。因此变成了
val maxLengthFruit = list.maxBy { it.length }

函数内联:

        lambda可以让你更灵活地编写应用,但是,灵活也是要付出代价的。 在JVM上,你定义的lambda会以对象实例的形式存在)JVM会为所有同lambda打交道的变量分配内存,这就产生了内存开销。更糟的是, lambda的内存开销会带来严重的性能问题。幸运的是, kotlin有一种优化机制叫内联,有了内联,JVM就不需要使用lambda对象实例了,因而避免了变量内存分配。哪里需要使用lambda,编译器就会将函数体复制粘贴到哪里。>使用lambda的递归函数无法内联,因为会导致复制粘贴无限循环,编译会发出警告。

        简单理解当一个函数参数是lambada对象是不会为其分配内存,而是把它转换成很多语句去执行


函数引用:

        要把函数作为参数传给其他函数使用,除了传lambada表达式,kotlin还提供了其他方法,传递函数引用,函数引用可以把一个具名函数转换成一个值参,使用lambada表达式的地方,都可以使用函数引用,使用时要在函数名加::

fun main(){
showOnBoard("牙膏",::getDisountWord)
}
private fun getDisountWord(goodsName: String,hour: Int):String{
    val currentYear = 2027
    return "${currentYear}年, 双11${goodsName}促销倒计时: $hour 小时"
}
fun showOnBoard(goodsName:String,getDiscountWords: (String ,Int)-> String){
    val hour: Int = (1..24).shuffled().last()
    println(getDiscountWords(goodsName,hour))
}

函数类型作为返回类型:

        函数类型也是有效的返回类型,也就是说可以定义一个能返回函数的函数

package com.example.myapplication

fun main(){
    val getDiscoutWords:(String) -> String = configDiscountWords()
    println(getDiscoutWords("牙膏"))
    //纠结为什么getDiscoutWords就变成getDiscoutWords("牙膏")因为赋值后他就相当于
    // val getDiscoutWords:(String) -> String= { goodsName: String ->
    // "${currentYear}年,双11${goodsName}促销倒计时:$hour"
    //这里的${currentYear}和${goodsName}都是在configDiscountWords()赋好值的
    }
}

fun configDiscountWords(): (String) -> String{
    val currentYear = 2007
    val hour:Int = (1..24).shuffled().last()
    return { goodsName: String ->
        "${currentYear}年,双11${goodsName}促销倒计时:$hour"

    }
}

        思考下 configDiscountWords函数下的两个变量为什么匿名函数里依然可以使用,这就叫做作用域共享,具名函数时共享不了的,就涉及到下个知识点

闭包:

        在Kotlin中,匿名函数能修改并引用定义在自己的作用域之外的变量,匿名函数引用着定义自身的函数里的变量, Kotlin中的lambda就是闭包。

        能接收函数或者返回函数的函数又叫做高级函数,高级函数广泛应用于函数式编程当中。

        kotlin文件和文件之间的作用域是同一个作用域所以在main方法外定义一个和别的文件重名的常量(const)会报错,所以在kotlin中一个函数相当于一个类,他会在函数中把作用域处理好


lambda与匿名内部类:

        为什么要在代码中使用函数类型?函数类型能让开发者少写模式化代码,写出更灵活的代码。Java 8支持面向对象编程和lambda表达式,但不支持将函数作为参数传给另一个函数或变量,不过Java的替代方案是匿名内部类。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值