kotlin:高阶函数和lambda表达式

  1. 高阶函数:kotlin提供的一种特殊的函数,可以将函数作为参数传入或者将函数作为返回值返回。
    • kotlin系统函数中提供了一系列的高阶函数,比如kotlin中的集合的操作函数,kotlin中的高阶函数:let,with,apply,use几个函数(当前文章着重学习高阶函数和lambda表达式,具体的高阶函数后续新开文章学习总结),即:


      kotlin高阶函数

      集合的fold函数

      fold函数使用
  2. 函数类型(Function Type)
    • 结合高阶函数,将函数作为参数或者作为返回类型,为了支持这种实现kotlin提供了函数类型这一概念并声明了函数类型的语法,整理如下:
      • 语法:(参数类型列表)-> 返回值类型:注意基础的函数类型的是参数类型列表,实例:(Int,Int)-> Int : 接受两个Int的参数,返回一个Int的返回值。
        • 参数的个数可以为null,即此时的语法() -> Int:没有参数返回一个Int的值,也可以没有返回值,即()-> Unit :此时需要注意的是Unit不能省略。
        • A.(B) -> C:函数类型提供一个接受者:即:表示一个可以对类型为 A 的接受者调用的函数, 参数类型为B, 返回值类型为 C. 对这种函数类型, 我们经常使用 带接受者的函数字面值。
          带有接受者的函数类型
        • 挂起函数(Suspending function)是一种特殊类型的函数, 它的声明带有一个特殊的 suspend 修饰符, 比如: suspend () -> Unit, 或者: suspend A.(B) -> C.
        • 带有参数名的参数列表:参数列表中可以只是参数类型 , 也可以加上参数的变量名称 , 参数名称可以用于说明参数的含义 , 增加函数类型的理解性


          带有参数名称的参数类型
        • 函数类型可空:函数类型 与 普通变量类型一样 , 也分为可空类型 , 非空类型 两类 。默认的函数类型都是非空类型 , 即函数定义时 , 需要对其进行初始化 , 或延迟初始化 。可空的函数类型声明时 , 需要在函数类型外部加上括号 , 并在右侧添加 ? 可空符号 :
          ( ( 参数列表 ) -> 返回值类型 ) ?


          可空函数类型
          • 函数类型也可以使用括号组合在一起: (Int) -> ((Int) -> Unit)


            嵌套函数类型
          • 可以给函数类型指定别名:typealias ClickHandler = (Button, ClickEvent) -> Unit
          • 函数类型的实例化:lambda表达式,匿名函数,已声明的函数,函数变量,函数类型派生类。
            • lambda表达式:val add1:(Int,Int) -> Int = {a:Int,b:Int -> a+b}:语法上需要注意的是:函数类型的语法:()-> Int lambda表达式的语法:{a:Int,b:Int -> a+b},整体的理解: 变量关键字 变量名:()-> 返回值类型,Int = {a:Int,b:Int -> a+b} 整个是返回值类型。
            • 匿名函数:var add2 : (Int, Int) -> Int = fun (a : Int, b : Int) : Int {return a + b}
            • 已声明的函数:需要注意的是::的使用方式,顶层函数可以直接使用:: 类中的函数使用类::函数来实例化函数类型后给变量。


              通过已声明的函数来实例化函数类型
            • 函数变量:已经声明的函数类型属性 , 可以是顶层属性 , 成员属性 , 扩展属性 即:


              函数变量初始化函数类型
            • 函数类型的派生类:我去直接拿一个类实现一个函数类型,在其重写函数invoke中返回数值类型,函数类型可以看做一个接口 , 类可以实现该接口 , 在实现类中实现具体的函数操作 , 该 函数类型接口的实现类 , 可以赋值给函数类型变量


              函数类型派生类实例化函数类型
              • 针对上面这几项可以参考下面的参考文章,参考文章说明的更详细包括事例更有代表性。
            • 函数类型的自动推断:像kotlin的参数似的,kotlin可以根据第一次赋值推断出参数的类型,所以可以不直接指定参数的类型,函数类型的返回值类型,kotlin也可以通过lambda或者匿名函数或者其他几种实例化方式推断出返回值的类型,还有函数类型的参数类型也可以通过lambda几种实例化进而推断出类型,所以二者都可以省略,需要注意的是kotlin推断不出其对应的类型的时候 参数类型和返回值类型都不能省略。比如Unit不能够省略。


              image.png
              • 带有接受者的函数类型和不带有接受者的函数类型转换:
                • 转换方式:前者转换为后者方式:将接受者对象作为第一个参数传递给后者,即后者在前者参数的基础上多一个参数,此参数为接受者对象。


                  函数类型转换

                  函数类型的转换2
              • 函数类型的调用:
                • 函数类型的实现函数是invoke函数,所以通过变量名的invoke调用即可以调用声明的这个函数类型。即变量名.invoke(参数)
                • 直接调用 : 也可以通过 函数类型变量名(参数列表) 直接调用该函数 , 将该变量名称当做函数名称来使用,即 变量名(参数)
  3. lambda表达式:
    • lambda表达式的语法:{ x : int ,y:Int -> x+y }
      • kotlin中lambda表达式始终用花括号包围,注意参数部分没有用括号括起来,箭头可以把实参列表和lambda的函数体隔开
      • 其中 箭头 -> 前的部分是参数,箭头后面是函数体
      • 参数 -> 函数体:多个参数中间使用,隔断,参数的类型若是kotlin能够自动推断出来可以不直接指明其类型。
      • lambda表达式的函数体可以是单行也可以是多行,最后一行默认是lambda表达式的返回值需要注意的是最后一行返回值的类型必须和lambda表达式变量声明的返回值的值类型保持一致,若不一致则会出现异常。
      • 由lambda表达式的语法可知:lambda表达式是不能够直接声明返回值的类型的,通常是由其函数体部分的最后一句语句推断出来的。
    • lambda表达式类型(变量)完整语法:val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }


      lambda语法

      备注:

      • 常量关键字 常量名称 : 参数 -> 返回类型 = { lambda表达式 }
      • 参数声明在大括号中,多个参数使用,隔开,0参数则()表示,单参数使用(参数)表示,参数中的某个参数也可以是一个参数类型(lambda表达式或者匿名函数等实例化即可) 参数可选即kotlin若能通过lambda表达式推断出参数的类型则语法中的参数类型(大括号)可以省略。
      • lambda若能够自动推断出返回值的类型则返回类型(变量声明的返回值类型)可以省略,但是Unit不能省略,因为kotlin是默认函数体的最后一行是返回值所以倘若不需要返回值则必须声明Unit(此处的声明是函数类型的语法声明所以Unit不能去掉)
      • 由于参数类型中的参数类型和返回值类型可以省略所以此时省略后的语法:val sum = { x: Int, y: Int -> x + y }


        lambda表达式作为变量
      • 针对一个高阶函数,倘若高阶函数的最后一个参数是lambda表达式,那么此函数调用的时候可以将最后一个参数(lambda表达式)放到函数参数大括号的外面,即:


        尾缀lambda表达式
      • 倘若lambda表达式仅仅有一个参数,即其参数唯一的时候此时lambda表达式可以不声明参数即可以忽略->前面的语法,直接去写表达式的函数体,此时唯一参数可以使用关键字it标识,即:


        it关键字
        • 常规lambda表达式是没有return语句的,最后一句语句就是返回值,返回值类型就是lambda表达式的返回值类型,如果使用 带标签限定的 return 语法, 你可以在 Lambda 表达式内明确地返回一个结果值(带标签限定的return语法:和标签限定this一致,通过标签标明return指向的那个对象,即return@filter表示 该返回值是函数filter的返回值). 否则, 会隐含地返回 Lambda 表达式内最后一条表达式的值.


          lambda表达式返回值
        • 在高阶函数调用的时候,需传入的lambda表达式,如果 Lambda 表达式的某个参数未被使用, 你可以用下划线来代替参数名:


          lambda表达式:下划线
        • Lambda表达式的解构:此处不详细描述,放到对应的解构模块去解析。
  4. 匿名函数:kotlin中函数的声明语法中不声明对应的函数名则被称为匿名函数:
    • 语法:fun(参数) :返回值 { 函数体}
    • 匿名函数和lambda表达式的区别:
      • lambda表达式语法:{参数-> 函数体},由其语法可了解到 lambda表达式是没有返回值返回的,通常根据其函数体的最后一句语句判断出返回值类型,若想直接声明返回值的类型则可以通过匿名函数来声明。
      • lambda表达式是没有return语句的,所以lambda表达式是不能够直接返回的,若返回需要从lambda表达式所属的函数中返回,但是匿名函数则不然,匿名函数则存在return语句可以在自己的函数体执行完毕后直接返回。
    • 和函数相比,匿名函数的区别是省略了函数名称,其函数体可以是单行也可以是多行,若单行可以省略掉{},此时成为匿名函数表达式(使用=替换掉原有的{}),即:


      匿名函数表达式
    • 匿名函数的参数类型和返回值类型若能够自动推断出来则可以省略掉其类型声明,若函数体是多行且没有返回值的时候则必须声明Unit,和java一致,没有返回值则必须声明void一致。
    • 匿名函数作为高阶函数的最后一个参数的时候,在调用的时候匿名函数不能放到高阶函数的大括号外部(参数),能够放到其外部的仅有lambda表达式。
  5. 闭包:
    • 闭包:在java中线程或者监听方法中,若要是想访问外部函数中声明的局部变量则必须将其定义为final,且在其内部不能够修改局部变量(final的局部变量不被修改),对于此情况 kotlin提供了闭包的概念,在闭包中可以直接访问外部函数中的局部属性,对于var声明的外部属性还可以修改属性。
    • 闭包的原理:针对闭包由其编译后的JAVA文件可知:将其外部属性编译成为一个final的局部对象变量(比如局部变量是int 编译后变量名对应的是Integer对象)且这个局部对象变量还声明了一个属性其属性对应的值是先前局部变量的值,即int i = 5编译后是:Integer i = new Integer(),i.element = 5所以在闭包中不仅可以访问这个属性还可以修改这个属性:


      kotlin闭包

      kotlin闭包编译后的代码
    • lambda表达式,匿名函数的函数体都可以看做其闭包,即在其函数体内都可以访问外部函数声明的局部属性甚至可以直接修改其外部属性。


      闭包

参考文章:
kotlin:函数类型
kotlin:常用的高阶函数
kotlin:list的常见操作函数
kotlin:lambda表达式
kotlin:lambda表达式
kotlin:闭包原理
kotlin:闭包

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容