Kotlin学习笔记(14)- lambda

系列文章全部为本人的学习笔记,若有任何不妥之处,随时欢迎拍砖指正。如果你觉得我的文章对你有用,欢迎关注我,我们一起学习进步!
Kotlin学习笔记(1)- 环境配置
Kotlin学习笔记(2)- 空安全
Kotlin学习笔记(3)- 语法
Kotlin学习笔记(4)- 流程控制
Kotlin学习笔记(5)- 类
Kotlin学习笔记(6)- 属性
Kotlin学习笔记(7)- 接口
Kotlin学习笔记(8)- 扩展
Kotlin学习笔记(8)- 扩展(续)
Kotlin学习笔记(9)- 数据类
Kotlin学习笔记(10)- 泛型
Kotlin学习笔记(11)- 内部类和嵌套类
Kotlin学习笔记(12)- 委托
Kotlin学习笔记(13)- 函数式编程
Kotlin学习笔记(14)- lambda

在上一篇《Kotlin学习笔记(13)- 函数式编程》的最后我提到lambda为函数式编程提供了更多更好的实现,如果你还不太了解什么是函数式编程,那么可以看看我的上一篇文章。那么我们首先来看看什么是lambda,在百度百科上是这么说的:

“Lambda 表达式”(lambda expression)是一个匿名函数,Lambda表达式基于数学中的λ演算得名,直接对应于其中的lambda抽象(lambda abstraction),是一个匿名函数,即没有函数名的函数。Lambda表达式可以表示闭包(注意和数学传统意义上的不同)。

一、Lambda的定义

看上面的说法有点抽象,有点不明所以,我们先来看一个栗子

class Num {
    fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){
        println("calc : ${calc(a,b)}")
    }
}

fun main(args : Array<String>){
    val num = Num()
    num.logic(1, 2, {x,y -> x+y})
}

// 输出
calc : 3

这个栗子和上一篇文章很像,只是在调用的时候改成了Lambda方式:num.logic(1, 2, {x,y -> x+y}),其中{x,y -> x+y}就是我们今天要讲的Lambda表达式,它的完整格式应该是这样

{ x: Int, y: Int -> x + y }

写成java代码是这个样子:

public int sum(int x, int y){
    return x+y;
}

可以很明显看出有几个规则:

  1. 参数写在->左边,格式与普通函数的参数格式一样,多个参数用逗号,分割
  2. 参数的类型可选,可忽略,编辑器会根据上下文推断(这就和普通函数不一样了吧,有种“我知道你懂得,所以就不写了”的感觉有木有,知己的感觉啊……)
  3. 函数体跟在->右边
  4. Lambda表达式总是被大括号{}包围着

二、Lambda中的一些约定

  1. 如果 Kotlin 可以自己计算出签名,它允许我们不声明唯一的参数,并且将隐含地为我们声明其名称为 it。其实通常情况下它都可以自己计算出签名,也就是说,如果函数字面值只有一个参数, 那么它的声明可以省略(连同 ->),其名称是 it

    fun oneParams(one : (Int) -> Int){
        println("oneParams : ${one(5)}")
    }
    
    fun main(args : Array<String>){
        val num = Num()
        num.oneParams({it * 2})
    }
    
    // 输出
    oneParams : 10
    

    说到省略,其实还有一种情况可以省略->,大家应该也能想到,就是无参函数。

    fun empty(emptyM : () -> Unit){
        emptyM()
    }
    
    fun main(args : Array<String>){
        val num = Num()
        num.empty({println("empty method")})
    }
    
    // 输出
    empty method
    
  2. 如果Lambda中的某个参数没有用到,可以用下划线_代替,也就是说,省了好多请名字的脑细胞有木有!这个特性从1.1开始可以使用,现在你看到的时候应该已经不止1.1了吧,所以这个限制看看就好~

    fun unusedParams(unused : (Int,Int) -> Int){
        println("unusedParams : ${unused(5,10)}")
    }
    
    fun main(args : Array<String>){
        val num = Num()
        num.unusedParams { _, used -> used * 2 }
    }
    
    // 输出
    unusedParams : 20
    
  3. 如果函数的最后一个参数是一个函数,那么我们在用Lambda表达最后一个函数参数的时候,可以把它放在括号()外面,所以下面的写法是等价的。

    class Num {
        fun logic(a: Int, b: Int, calc: (Int, Int) -> Int){
            println("calc : ${calc(a,b)}")
        }
        fun sum(a: Int, b: Int) = a + b
    }
    
    fun main(args : Array<String>){
        val num = Num()
        // 写法1
        num.logic(1, 2, {x : Int,y : Int -> x+y})
        // 写法2
        num.logic(1, 2){x : Int,y : Int -> x+y}
        // 写法3
        num.logic(1, 2){x,y -> x+y}
    }
    

    那么这么写有什么好处呢?难道只是位置变了一下?当然不是,不要忘记,Lambda的->后面是方法体,也就是很多时候不是想栗子中这样只有一行,如果有多行的话,体会一下他们的区别:

    num.logic(1, 2, {x,y ->
        println("extra line")
        x+y
    })
    
    num.logic(1, 2){x,y ->
        println("extra line")
        x+y
    }
    

    是不是感觉下面的写法要优雅很多,也明确很多?

  4. 其实在上面一点应该已经能看出,如果有需要的话,Lambda会隐式的返回最后一个表达式的值,就像上面的最后一行x+y。当然,我们也可以显示的表达返回值,下面的写法还是一样的:

    // 写法1
    num.unusedParams { _, used ->
        println("print first")
        return@unusedParams used * 2
    }
    
    // 写法2
    num.unusedParams { _, used ->
        println("print first")
        used * 2
    }
    

三、匿名函数

看了这么多,我们发现一个问题,Lambda的返回类型全是自动推断的,虽然很人性化,但是有时候我们就是想自己指定类型怎么办?当然是有办法的,那就是匿名函数

fun(x:Int, y:Int):Int{return x+y}

匿名函数看起来非常像一个常规函数声明,除了其名称省略了。其函数体可以是表达式(如上所示)或代码块。由于这已经不算正经的Lambda,所以它不需要被大括号{}包裹,也不能像Lambda一样写在括号()外,而调用也是直接调用。

num.logic(1, 2, fun(x:Int, y:Int):Int{return x+y})

四、闭包

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

var sum = 0
ints.filter { it > 0 }.forEach {
    sum += it
}
print(sum)

五、小结

其实没什么小结,关于更多的函数式的高级应用、复杂应用,个人也正在学习,大家互相交流。

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

推荐阅读更多精彩内容