首页 > 其他分享 >kotlin lambda

kotlin lambda

时间:2022-11-11 00:01:36浏览次数:37  
标签:return Int kotlin invokeWith factor println lambda

一、lambda表达式的语法

{parameter list -> body}

kotlin和java的lambda表达式的语法存在一定程度的差异:

1、kotlin在通常的情况下不允许有return语句,而java则可以有零个或者多个return语句

2、kotlin有隐式的参数it:fun isPrime(n: Int) = n > 1 && (2 until n).none({n % it == 0})

3、lambda的语法格式:fun walkTo(n: Int, action: (Int) -> Unit) = (1..n).forEach(action); 该函数接收的action参数是一个lambda表达式,该表达式接受一个int类型的参数,并且返回值是Unit; 在kotlin中,Unit就是java里面的void

4、kotlin和java的一个共通点是lambda尾随的特性:如上的walkTo可以有如下的调用:walkTo(5) {i -> print(i)}

5、lambda可以作为函数的返回值返回

6、lambda有闭包的概念,可以捕获外部的变量

var factor = 2
val doubled = listOf(1, 2).map {it * factor}
factor = 0
doubled.forEach{println(it)}// 输出 2, 4

如上在map的lambda中捕获了factor,此时的factor是2,所以该lambda表达式捕获到了factor等于2的值;接下去虽然factor=0,但是已经过了lambda的区域;虽然最后doubled的输出是在factor=0之后

7、lambda在特殊情况下带return语句

lambda有两种情况可以带return,一种是使用标签的方式,一种是内联的方式

这里说下使用标签的方式

fun invokeWith(n: Int, action: (Int) -> Unit) {
    println("enter invokeWith $n")
    action(n)
    println("exit invokeWith $n")
}
fun caller() {
    (1..3).forEach{ i ->
        invokeWith(i) here@ {
            println("enter for $it")
            if (it == 2) {
                return@here
            }
            println("exit for $it")
        }
    }
    println("end of caller")
}
caller()

如上的输出如下所示
/*
enter invokeWith 1
enter for 1
exit for 1
exit invokeWith 1
enter invokeWith 2
enter for 2
exit invokeWith 2
enter invokeWith 3
enter for 3
exit for 3
exit invokeWith 3
end of caller
*/

通过上面可以看出,return@here只是当it==2时候返回到了这个invokeWith(i)的标记位置,这里return@invokeWith也可以产生相同的效果

 

8、lambda的内联

lambda的内联是将lambda函数对应的字节复制到所在函数的调用位置,而不止是通过函数指针去调用远处的某个函数

回到第5条关于lambda作为函数返回:内联的lambda函数不能作为返回值返回;因为内联的lambda严格来说不算是有函数指针,返回值没办法返回对应函数内的某块内存

回到第6条关于捕获外部变量:

var factor = 2
val doubledAlso = sequenceOf(1,2).map{it * factor}
factor = 0
doubledAlso.forEach{println(it)}
如上的输出是
0
0

由于sequenceOf对应的lambda是内联的,所以这里对应的其实是该lambda的一整块内存,lambda中的factor对应的是外部factor的地址,所以当factor后面设置为0再调用显示的时候则lambda中的factor也是为0

回到第7条关于lambda内部使用return

fun caller1() {
    (1..3).forEach {i ->
        println("in foreach for $i")
        if (i == 2) {
            return
        }

        invokeWith(i) {
            println("enter for $it")
            if (it == 2) {
                return@invokeWith
            }
            println("exit for $it")
        }
    }
}
caller1()
调用的结果是:
in foreach for 1
enter invokeWith 1
enter for 1
exit for 1
exit invokeWith 1
in foreach for 2

如上所示,在i==2的时候整个forEach的循环调用被return掉了

所以内联其实就是将整个函数拷贝到使用的内联的位置,然后在那里做调用;该位置的return相当于整个函数的return

8、inline对应的noinline

刚才在关于第5点的内容中说的内联lambda不能作为返回值,但是如果是内联函数,但是要作为返回值该如何呢? 这里可以使用noinline

inline fun invokeTwo(n: Int, action1: (Int) -> Unit, noinline action2: (Int) -> Unit): (Int) -> Unit {
    println("enter invokeTwo $n")
    action1(n)
    println("exit invokeTwo $n")
    return action2
}

如上所示,在invokeTwo设置为inline的时候,将action2标记为noinline则可以将action2当作返回值返回否则不可以

9、inline对应的crossinline

如果我们既要将lambda当成内联函数,又要将该lambda返回,则可以使用crossinline关键字

inline fun invokeTwo(n: Int, action1: (Int) -> Unit, crossinline action2: (Int) -> Unit): (Int) -> Unit {
    println("enter invokeTwo $n")
    action1(n)
    println("exit invokeTwo $n")
    return {input: Int -> action2(input)} // 既有return又要返回,则可以使用crossinline来做标记
}

fun callInvokeTwo() {
    invokeTwo(1, {i ->
    if (i == 1) {return}
    report(i)}, {i ->
    if (i == 2) {return} // 这里使用了return所以需要用inline
    report(i)})
}
callInvokeTwo()

 

标签:return,Int,kotlin,invokeWith,factor,println,lambda
From: https://www.cnblogs.com/czwlinux/p/16879272.html

相关文章

  • Android开发Compose版本、Kotlin 版本、KSP版本版本对应关系
    Android开发Compose版本、Kotlin版本、KSP版本版本对应关系是要遵循官方给出的,不然容易出锅甚至编译都不过,即使编译通过也可能导致潜在崩溃ComposeCompiler版本和兼......
  • Kotlin 中的 Lambda 与 Inline
    在Kotlin中,有很多很酷很实用的特性,比如Lambda和高阶函数,利用这些特性,我们可以更加快速的实现开发,提升效率。比如我们实现一个捕获Throwable,安全执行部分代码的高阶函数fun......
  • 探究Kotlin的局部方法
    在Kotlin中,定义方法很有趣,不仅仅因为方法的关键字是fun(function前几个字符),还是因为你会惊奇的发现,它允许我们在方法中定义方法。如下funmethodA(){funmethodB(){......
  • 有点意思的Kotlin的默认参数与JVMOverloads
    在Java中,当我们定义一个类的时候,总会出现一些变量是必须要填写的,而另一些是可选的。比如像下面这样,我们定一个Person类,其中name是必须填写的,而性别sex和isChinese可选,如果不......
  • kotlin 委托
    我们经常使用的其实是继承,但是相对于继承使用委托的耦合性会更低。使用继承则代码相对会比较简单,但是使用委托则会比较复杂一、假设有interfaceWorker、classJavaProgr......
  • JvmMultifile 注解在 Kotlin 中的应用
    接触过Kotlin之后,我们会利用其扩展方法特性创建很多便捷的方法来实现更好更快的编码。比如我们对于RxJava进行一些简单的扩展方法实现。下面的这段代码实现一个将任意的对象......
  • JvmName 注解在 Kotlin 中的应用
    JvmName注解是Kotlin提供的一个可以变更编译器输出的注解,这里简单的介绍一下其使用规则。应用在文件上未应用@JvmNamepackagecom.example.jvmannotationsampleimportand......
  • python 中 lambda函数
     Lambda函数用于创建匿名函数:001、>>>add1=lambdax:x+2>>>add1(100)102>>>add1(50)52 >>>abc=lambdax:x*2>>>abc(10)20>>>abc(0.8)1.6......
  • kotlin中ViewModel + ViewBinding使用实例
    android使用androidx后可以使用viewbinding了,因为是内生库,也蛮好用的。butterknife感觉已经在退环境了。文章列出ViewModel+ViewBinding,是MVVM模式的简单使用,没有涉及......
  • MybatisPlus Lambda表达式 聚合查询 分组查询 COUNT SUM AVG MIN MAX GroupBy
    一、序言众所周知,MybatisPlus在处理单表DAO操作时非常的方便。在处理多表连接连接查询也有优雅的解决方案。今天分享MybatisPlus基于Lambda表达式优雅实现聚合分组查询。......