Kotlin函数式编程笔记

Kotlin语言基础笔记

Kotlin流程控制语句笔记

Kotlin操作符重载与中缀表示法笔记

Kotlin扩展函数和扩展属性笔记

Kotlin空指针安全(null-safety)笔记

Kotlin类型系统笔记

Kotlin面向对象编程笔记

Kotlin委托(Delegation)笔记

Kotlin泛型型笔记

Kotlin函数式编程笔记

Kotlin与Java互操作笔记

Kotlin协程笔记

就像在Java的世界中,一切皆是对象。那么在函数式编程中当然一切皆是函数。函数式编程感觉像返璞归真,现在又火了起来。Kotlin作为一位这几年才出现的语言必然会支持函数式编程。在Kotlin中函数式一等公民,地位和对象一样高,你可以在方法中输入函数,也可以返回函数。相对于Scala的学院派风格,Kotlin则是纯的的工程派:实用性、简洁性上都要比Scala要好。怪不得我当年看Scala中感觉好像门槛有点高,上手比较难。

1. 高阶函数

高阶函数是将函数用作参数或者返回值的函数。Kotlin的Collection类型中有大量的这种高阶函数,例如:Iterable的filter函数

filter

其中predicate: (T) -> Boolean定义了一个函数变量,变量名是predicate,类型是(T) -> Boolean这样一个函数。这个函数表示输入参数是T类型,输出Boolean类型。那我们来定义这样一个函数,然后调用高阶函数Iterable.filter

fun isLargeThanFive(x: Int): Boolean = x > 5
fun main(args: Array<String>) {
     val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
     println(numbers.filter(::isLargeThanFive))  //打印[6, 7, 8]
}

注意:我们使用::来引用一个函数。

2. 匿名函数

匿名函数,其实就是没有函数名的函数。我们也可以使用匿名函数来实现上面的代码:

fun main(args: Array<String>) {
     val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
     println(numbers.filter(
               fun (x: Int):Boolean {
                    return x > 5
               }
          )
     )
     //or 写成一行
     //println(numbers.filter(fun(x: Int) = x > 5))
}

3. Lambda表达式

我们也可以使用更简单Lambda表达式来实现:

    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    numbers.filter({ it > 5 })
    //or 这样
    numbers.filter { it > 5 }

Lambda表达式是这样定义的:

  • lambda 表达式总是括在花括号中。
  • 其参数(如果有的话)在 -> 之前声明(参数类型可以省略)。
  • 函数体(如果存在的话)在 -> 后面。
  • 如果lambda表达式是该调用的唯一函数,则调用中的圆括号可以省略。
  • 如果函数的最后一个参数是一个函数,并且你传递一个 lambda 表达式作为相应的参数,你可以在圆括号之外指定它。

对于最后一点,我们可以看看Iterable.elementAtOrElse方法:

elementAtOrElse

这个方法是返回第index元素,如果不存在的话返回(Int) -> T的函数值,函数参数是index,返回T类型。我们可以看看如何调用:

    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    println(numbers.elementAtOrElse(10, { 100}))
    //或者可以这样。
    println(numbers.elementAtOrElse(10) {100})

我们现在来定义一个两个参数的lambda表达式:

    val max = { x: Int, y: Int -> if (x > y) x else y }
    //下面这句等同于上面这句代码。
    //val max: (Int, Int) -> Int = { x: Int, y: Int -> if (x > y) x else y }
    println(max(1, 2))

更复杂的,lambda表达式还可以返回一个lambda表达式:

    val sum = { x: Int ->  {y:Int -> x+y } }
    println(sum)  //打印(kotlin.Int) -> (kotlin.Int) -> kotlin.Int

    println(sum(2)(1))  //打印3

3.1 it单个参数的隐私名称

当lambda表达式只有一个参数时,那么它的声明可以省略(包括->)。可以用it代表lambda唯一的参数。

    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    numbers.filter({ it > 5 })
    //or 这样
    numbers.filter { it > 5 }

3.2 下划线用于未使用的变量(1.1版本起)

如果 lambda 表达式的参数未使用,那么可以用下划线取代其名称:

map.forEach { _, value -> println("$value!") }

4. 闭包

Lambda 表达式或者匿名函数,以及局部函数和对象表达式(object declarations)可以访问其 闭包,即在外部作用域中声明的变量。 与 Java 不同的是可以修改闭包中捕获的变量:

fun main(args: Array<String>) {
    val numbers = listOf(1, 2, 3, 4, 5, 6, 7, 8)
    var sum = 0
    numbers.filter { it > 5 }.forEach { sum += it }
    println(sum)  //打印21
}

5. 带接收者的函数字面值

使用匿名函数的语法,我们可以直接指定函数字面值的接收者类型。

val sum = fun Int.(other: Int): Int = this + other
println(1.sum(1))  打印2

当接收者类型可以从上下文推断时,lambda 表达式可以用作带接收者的函数字面值。

class HTML {
    fun body() {
        println("HTML BODY")
    }
}

fun html(init: HTML.() -> Unit): HTML { // HTML.()中的HTML是接受者类型
    val html = HTML()  // 创建接收者对象
    html.init()        // 将该接收者对象传给该 lambda
    return html
}

fun main(args: Array<String>) {
    html{
        body()
    }  //打印HTML BODY
}

这个特性可以让我们构建DSL语言,类似安卓中build.gradle中的语法。

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