侧边栏壁纸
博主头像
Z同学博主等级

工作磨平激情前,坚持技术的热忱。 欢迎光临Z同学的技术小站。 分享最新的互联网知识。

  • 累计撰写 274 篇文章
  • 累计创建 55 个标签
  • 累计收到 74 条评论

Kotlin 与Lambda表达式

Z同学
2021-07-20 / 0 评论 / 0 点赞 / 535 阅读 / 3,766 字
温馨提示:
本文最后更新于 2021-11-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

前言

主要用来介绍Lambda表达式的使用,以及它所精简的代码。

什么是Lambda

Lambda 其实是一个匿名函数,即没有函数名的函数。

它是基于数学中的λ演算 得名。之后各种开发语言分别引入了Lambda表达式的支持。例如C#,Java,C++,Python,Kotlin等等。

Lambda 与Kotlin

Kotlin从一开始,就支持Lambda表达式。

我们说过,Lambda表达式,就是一个匿名函数

在Kotlin中,将这种通过Lambda精简的匿名函数,称为高阶函数。

其实Lambda可以当一种表达式的写法规则而已。

实例:

val sum: (Int, Int) -> Int = { x: Int, y: Int -> x + y }

这是一个比较典型的lambda 表达式。其中花括号里面的内容才是Lambda表达式。

定义:Lambda表达式总是在花括号里面。完整语法形式的参数声明,都放在花括号内,并有可选的类型标注,函数体跟在 ->符号之后。该Lambda主体中的最后一个表达式会视为返回值。

上面的句子,我们还可以精简为:

val sum1 = { x: Int, y: Int -> x + y }

两者是等价的。这是基于kotlin 的特性进行的精简

在Kotlin之中,有一个约定: 如果函数的最后一个参数是函数,那么作为相应参数传入的Lambda表达式可以放在()之外:

val product = items.fold(1) { acc, e -> acc * e }

这种语法叫做 :拖尾lambda表达式

实例1:

//定义了一个函数,比较了两个传参
fun test1(i1: Int, i2: Int) = i1 > i2

fun main(array: Array<String>) {
    val s = test1(12, 10)
    println(s)

    //Lambda 表达式 实现 和test1没有关系了。我们这是创建了一个新的函数
    var lambda = { i1: Int, i2: Int -> i1 > i2 }
    println(lambda(12, 10))
}
//输出:
true
true

如果在lambda的返回参数之中添加更多的语句。那么最后一个表达式的值就是Lambda的值

实例2:

fun main(array: Array<String>) {

    val sum = { x: Int, y: Int ->
        println("接口将会返回$x+$y 的和")
        x + y
    }
    println(sum(1, 2))
}
//输出:
//接口将会返回1+2 的和
//3

实例3:

//实例 --创建一个数组
var ss = arrayListOf("ssa", "sda", "ad")
//利用 filter函数 筛选数组满足Lambda 表达式的结果。
var sss = ss.filter {
    //传参值 不等于ssa的数据
    !it.equals("ssa")
}
//得到结果
println(sss)

//输出:
[sda, ad]

实例4: 我们自己创建一个

//我们有一个人的对象。
class People(var name: String, var age: Int, var six: Int) {

    //它这个传参,就是一个高阶函数的实现。
    inline fun trunOut(predicate: (People) -> Boolean): Boolean {
        return predicate(this)
    }
}


fun main(array: Array<String>) {
    var people = People("Z同学", 18, 1)
    val jieguo = people.trunOut {
        it.age > 20 && it.six == 0
    }
    println(jieguo)
}

it 单个参数的隐式名称

一个lambda表达式中如果只有一个传参。那么可以直接用it来指代。

并且忽略-> 符号

实例1:

ints.filter { it > 0 }  // 这个Lambda表达式: {it :Int -> it> 0 }

我们使用it之后,编译器会自动帮我们替换成指定传参

实例2:

class People {
    var age = 10;
    fun maxBy(str: (People) -> Int) {
        println("得到的值是: $str")
    }
}

fun main(array: Array<String>) {
    val people = People()
    //第一种 全部数据输入情况下
    people.maxBy({ p: People -> p.age })
    //第二种Kotlin 约定 这种情况下可以将Lombda表达式放在括号外
    people.maxBy() { p: People -> p.age }
    //第三种 在编译器能够推导数据格式时,我们可以省略格式
    people.maxBy { p -> p.age }
    //第四种,当编译器能够推导数据格式,并且传参只有一个的时候。
    people.maxBy { it.age }
    
    //但是这种情况下的Lambda 不能抽象
    val sum = { x: Int -> x > 10 }
    //不能这样简写,因为编译器无法根据上下文确定x的参数类型
    val sum1 = { x -> x > 10 }
}

下划线用于未使用的变量-(Kotlin 1.1版本开始)

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

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

实例1:

//我们有一个人的对象。
class People(var name: String, var age: Int) {
    /**
     * 定义一个函数
     */
    fun test1(lmdd: (String, Int) -> String): String {
        return lmdd(name, age)
    }
}


fun main(array: Array<String>) {
    var people = People("Z同学", 18)
    var temp = people.test1 { _, i ->
        var s = ""
        when {
            i < 5 -> {
                s = "幼儿"
            }
            i < 16 -> {
                s = "未成年"
            }
            i > 60 -> {
                s = "老年人"
            }
            else -> {
                s = "成年人"
            }
        }
        s
    }
    println(temp)
}
//输出
成年人

带接收者的Lambda表达式

表达式形式: A.() -> C

优势:在lambda函数体可以无需任何额外的限定符的情况下,直接使用接收者对象的成员(属性和函数),也可以使用this访问接收者对象。

在Kotlin的标准库中,有提供了带接收者的lambda表达式: withapply

Kotlin源码样式:

@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    return receiver.block()
}
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
    contract {
        callsInPlace(block, InvocationKind.EXACTLY_ONCE)
    }
    block()
    return this
}

实例1:

class Test() {
    fun test() {
        println("打印数据参数")
    }
}

fun demo1(tt: Test.() -> Unit): Test {
    val temp = Test()// 创建一个接收者对象
    temp.tt() //将接收者对象传给tt Lambda
    return temp
}

fun main(array: Array<String>) {
    var te = demo1 {
        test()
    }
    te.test()
}
//输出
打印数据参数
打印数据参数

闭包

Kotlin之中支持函数中包含函数。

//这个函数,定义了返回值是一个高阶函数,
fun test(a: Int): () -> Int {
    var b = 3
    return fun(): Int {
        b++
        return a + b
    }
}

fun main(array: Array<String>) {
    var ss = test(1)
    println(ss) //这个时候 ss 是一个函数对象,所以直接打印会打印内存地址
    println(ss()) //执行了这个Lambda表达式
    println(ss()) //执行了这个Lambda表达式
    println(ss()) //执行了这个Lambda表达式
}

输出结果:

Function0<java.lang.Integer>
5
6
7
0

评论区