Kotlin-高阶函数,Lambda表达式,内联函数

文章目录

高阶函数以及Lambda表达式的使用

Kotlin中的函数属于一等公民,它可以被存储在变量中,也可以作为参数传递给高阶函数(将函数作为参数或者返回值的函数)并从中返回

kotlin 复制代码
 var func: (Int)->Unit

变量func就表示一个参数为Int类型,没有返回值的函数

我们还可以为函数类型起别名来缩短名称

kotlin 复制代码
typealias LambdaExample = (Int)->Unit

fun main(){
    var func: LambdaExample
}

可以使用::来引用一个现成的函数

kotlin 复制代码
fun main(){
    var func: (String) -> Int = ::test
    println(func(""))
}

fun test(str: String): Int {
    return 666
}

还可以直接用匿名函数实现

kotlin 复制代码
fun main(){
    var func: (String) -> Int = fun(str: String): Int {
        return 10
    }
    println(func(""))
}

简写成:

kotlin 复制代码
fun main(){
    var func: (String) -> Int = fun(str: String): Int = 10
    println(func(""))
}

使用Lambda的方式:

kotlin 复制代码
fun main(){
    var func: (String) -> Int = { 
        10
    }
    println(func(""))
}

Lambda默认最后一行作为它的返回值,而且只有一个参数的情况下那个参数为 it (如果是匿名函数直接用参数名就行了)

kotlin 复制代码
fun main(){
    var func: (String) -> Int = {
        println(it)
        10
    }
    println(func("hello"))
}
kotlin 复制代码
fun main(){
    var func: (String) -> Int = {
        println("获取到参数$it")
        10
    }
    println(func("hello"))
}

如果有两个参数的话,就需要手动指定参数的名字

kotlin 复制代码
fun main(){
    var func: (String, String) -> Int = { a,b->
        println(a)
        println(b)
        10
    }
    println(func("hello", "Kotlin"))
}

如果我们不想用第一个参数,就设置成_表示不使用

kotlin 复制代码
fun main(){
    var func: (String, String) -> Int = { _,b->
        println(b)
        10
    }
    println(func("hello", "Kotlin"))
}

高阶函数的Lambda使用

kotlin 复制代码
fun test(func: (String) -> Int){
    println(func("hello"))
}

fun main(){
    test { 
        println(it)
        20
    }
}

更复杂的情况:

kotlin 复制代码
fun test(a: Int, b: String, func: (String) -> Int){
    println(a)
    println(b)
    println(func("hello"))
}

fun main(){
    test (10, "abc") {
        println(it)
        20
    }
}
kotlin 复制代码
fun test(a: Int, func: (String) -> Int, b: String){
    println(a)
    println(b)
    println(func("hello"))
}

fun main(){
    test (10,  {
        println(it)
        20
    }, "abc")
}

最后需要注意的是,在Lambda中没有办法直接使用 return 语句返回结果,而是需要用标签

kotlin 复制代码
fun main(){
    val func: (Int) -> String = test@{
        if(it > 10) return@test "我是提前返回结果"
        println("我是正常情况")
        "收到的参数为$it"
    }
    println(func(1))
    println()
    println(func(11))
}

如果函数调用的尾随Lambda表达式,默认的标签名字就是函数的名字

kotlin 复制代码
fun test(func: (Int) -> String) {
    println(func(11))
    println()
    println(func(10))
}

fun main(){
    test {
        if(it > 10) return@test "我是提前返回结果"
        println("我是正常情况")
        "收到的参数为$it"
    }
}

内联函数

在Kotlin中,使用高阶函数可能会影响运行时的性能: 每个函数都是一个对象, 而且函数内可以访问一些局部变量,这可能造成额外开销

为了优化性能,开销可以通过内联函数来消除。使用inline关键字能让方法的调用在编译时,直接替换为方法的执行代码,比如说下面的这段代码:

kotlin 复制代码
fun main() {
    test()
}

//添加 inline 表示内联函数
inline fun test(){
    println("这是一个内联函数")
    println("这是一个内联函数")
    println("这是一个内联函数")
}

由于test函数是内联函数,在编译之后,会原封不动地把代码搬过去

kotlin 复制代码
fun main() {
    println("这是一个内联函数")
    println("这是一个内联函数")
    println("这是一个内联函数")
}

同样的,如果是一个高阶函数,效果就更好了:

kotlin 复制代码
fun main(){
    test { println("打印: $it") }
}

inline fun test(func: (String) -> Unit) {
    println("这是一个内联函数")
    func("hello word")
}

由于test函数是内联的高阶函数,在编译之后,不仅会原封不动地把代码搬过去,还会自动将传入的函数参数贴到调用的位置

kotlin 复制代码
fun main(){
    println("这是一个内联函数")
    val it = "hello word"
    println("打印: $it")
}

内联会导致编译出来的代码变多,但是换来了性能上的提升,不过这种操作仅对高阶函数有显著效果,普通函数实际上完全没有内联的必要,也提升不了多少性能

注意,内联函数默认会将参数也进行内联。内联的函数形参,无法作为值给到变量,只能调用:

使用noinline修饰符可以禁止参数的内联关系

kotlin 复制代码
fun main(){
    test { println("打印: $it") }
}

inline fun test(noinline func: (String) -> Unit) {
    println("这是一个内联函数")
    func("hello word")
    val a = func
}

同样的,由于内联,导致代码被直接搬运,所以Lambda中的return语句可以不带标签,但这种情况可能会导致直接返回:

kotlin 复制代码
fun main(){
    test {
        if (it == "hello word") return
        println("打印: $it")
    }
    println("程序结束")
}

inline fun test(func: (String) -> Unit) {
    println("这是一个内联函数")
    func("hello word")
}
kotlin 复制代码
fun main(){
    test {
        if (it == "hello word") return@test
        println("打印: $it")
    }
    println("程序结束")
}

inline fun test(func: (String) -> Unit) {
    println("这是一个内联函数")
    func("hello word")
    println("test结束")
}

这语法太糖了,@test就作用到func,test函数剩下的部分正常执行

内联函数的优势

  1. 减少内存消耗:内联函数避免了创建Lambda表达式的额外对象,从而减少了内存消耗。
  2. 提升性能:通过将函数体的代码直接复制到调用处,内联函数避免了函数调用的开销,从而提高了程序的性能。
  3. 简化代码结构:内联函数可以直接在调用处展开,使代码更加简洁、紧凑,提高了可读性和可维护性。

注意事项

  1. 慎重选择内联函数:内联函数适用于函数体较小的情况,如果函数体过大,内联将导致代码膨胀,可能会增加可执行代码的大小。
  2. 禁止内联的情况:某些情况下,我们可能不希望函数内联,例如递归函数、高阶函数的参数会被存储在变量中并多次调用的情况。在这种情况下,可以使用noinline修饰符来禁止参数的内联关系。

总结

内联函数是Kotlin中提供的一种优化性能的机制,通过将函数体的代码直接复制到调用处,减少了Lambda表达式的额外对象创建和函数调用的开销。使用内联函数可以提高程序的性能,并简化代码结构。然而,需要慎重选择内联函数,并注意在必要的情况下使用noinline修饰符来禁止参数的内联关系。

相关推荐
Scott9999HH5 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
码智社6 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海6 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖7 小时前
JDK 26 新特性详解
java·开发语言
马优晨8 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区10 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大10 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai10 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
এ慕ོ冬℘゜10 小时前
前端基础:什么是时间戳?JS获取时间戳三种方法与实战用途
开发语言·前端·javascript
执明wa11 小时前
LayoutInflater详解: XML是如何变成View的?
android·xml·开发语言·android studio