Kotlin-23-inline+noinline+crossinline

本文深入探讨Kotlin中的inline、noinline、crossinline关键字的使用与原理,解析内联函数如何优化高阶函数的运行效率,以及在实际开发中如何合理运用这些特性。

目录

1、inline 背景

2、inline 原理

3、noinline

4、crossinline

5、注意


 

1、inline 背景

inline---内联函数

当我们在使用高阶函数的时候,因为除了高阶函数本身是个函数以外,它的参数或者返回值也是一个Lambda函数,lambda函数内部还有局部变量,当在编译运行的时候,因为每一个Lambda函数都是一个对象,并且还会捕获一个闭包及闭包内会访问到的变量。 这样在内存分配(对于函数对象和类)和虚拟机调用上都会加大运行时间开销。

为了解决高阶函数所带来的额外开销,kotlin加入了inline关键字。

注意:过多的使用inline关键字会对编译器造成很大的性能压力,所以我们建议只在高阶函数中使用inline关键字。

2、inline 原理

代码在编译以后,会将内联函数的函数体复制到调用处。

下面左边是我们的inline函数,右边是我们编译后的class文件。

从编译后的class可以看出,inline的函数体会被直接复制到调用该内联函数的地方。

                          

3、noinline

因为inline是用来修饰高阶函数的,又因为被inline修饰的高阶函数,其参数中的lambda函数也会隐式变成inline函数,但如果我们不想要将lambda参数内联化的话,就可以使用noline关键字。

下面左边是kotlin代码,右边是编译后的class文件,绿色框中,就是我们内联化的 lambda函数a,红色就是没有被内联化的lambda函数b。

        

4、crossinline

crossinline的作用就是:不允许inline的lambda函数中断外部函数执行。

  • 在kotlin中,函数内部lambda是不允许中断外部函数执行的。(如果有return检查期会报错)
fun test1(a:()->Unit){
    a.invoke()
    return
    println("我在return后面")
}

fun main() {
    test1 { println("我是Lambda函数a") 
    //return--------------------------------报错,无法return
    }

    println("我在test1后面")
}
//输出结果
我是Lambda函数a
我在test1后面
  • inline修饰的lambda可以中断外部函数调用(原理:会将return复制到main函数中,所以return后面的语句就无法执行了)
inline fun test1(a: () -> Unit) {
    a.invoke()
    return
    println("我在return后面")
}

fun main() {
    test1 {
        println("我是Lambda函数a")
        return
    }
    println("我在test1后面")
}
//输出结果
我是Lambda函数a
  • 在inline的修饰的高阶函数中,将参数中的lambda函数用crossinline修饰就不会中断外部函数的执行。
inline fun test1(crossinline a: () -> Unit) {
    a.invoke()
    return
    println("我在return后面")
}

fun main() {
    test1 {
        println("我是Lambda函数a")
//        return-----------------------报错,无法使用return
    }
    println("我在test1后面")
}
//输出结果
我是Lambda函数a
我在test1后面

5、注意

break 和 continue 在内联的 lambda 表达式中目前还不可用。



 

 

 

这段 Kotlin 代码中使用了几个函数修饰符:`inline`、`crossinline` 和 `noinline`,它们是 Kotlin 中用于控制函数内联行为的关键字。理解它们的作用和区别,有助于我们写出更高效、安全的代码。 --- ### 🧠 先看代码结构: ```kotlin suspend inline fun <reified T : Any> launchRequest( crossinline block: suspend () -> CResponse<T>, noinline onSuccess: ((T?) -> Unit)? = null, noinline onError: ((Exception) -> Unit)? = null, noinline onComplete: (() -> Unit)? = null ) { try { val response = block() onSuccess?.invoke(response.data) } catch (e: Exception) { // 异常处理 onError?.invoke(e) } finally { onComplete?.invoke() } } ``` 这是一个用于封装网络请求的通用函数,使用了协程(`suspend`)和内联(`inline`)函数技巧。 --- ## 🔍 关键字解释 ### ✅ 1. `inline` - **作用**:将函数体在调用处**直接展开**,避免创建额外的函数对象,提升性能。 - **适用场景**:适用于高阶函数(函数参数是函数),尤其是传入的函数参数只用于调用一次或少量几次。 - **代价**:会增加生成的字节码体积,因为函数体被复制到每个调用处。 **在这段代码中的使用:** ```kotlin suspend inline fun <reified T : Any> launchRequest(...) ``` - 因为 `launchRequest` 是一个封装网络请求的通用函数,频繁被调用,使用 `inline` 可以减少运行时开销。 - 同时,`reified` 也要求函数必须是 `inline`,因为只有内联函数才能访问具体类型信息。 --- ### ✅ 2. `crossinline` - **作用**:防止传入的 lambda 表达式中使用 `return`(非局部返回),确保 lambda 不会破坏内联函数的控制流。 - **使用场景**:当你将 lambda 作为参数传递给另一个函数时(比如嵌套调用),为了避免 lambda 中的 `return` 导致不可预测行为。 **在这段代码中的使用:** ```kotlin crossinline block: suspend () -> CResponse<T> ``` - `block` 是一个 lambda,被传入到 `launchRequest` 中,并在函数体内调用。 - 由于 `block` 被 `inline` 展开,为了避免它内部使用 `return@block` 或 `return` 导致整个函数提前返回,使用 `crossinline` 来限制。 **例如:** ```kotlin crossinline` 会禁止以下行为: block() return@block // ❌ 编译错误 ``` --- ### ✅ 3. `noinline` - **作用**:阻止某个函数参数被内联展开,即使外层函数是 `inline`。 - **使用场景**:当某些函数参数会被多次调用、或作为回调保存、或不希望被内联时。 **在这段代码中的使用:** ```kotlin noinline onSuccess: ((T?) -> Unit)? = null noinline onError: ((Exception) -> Unit)? = null noinline onComplete: (() -> Unit)? = null ``` - 这些回调函数可能被保存、多次调用,或作为参数传递给其他函数。 - 如果将它们也 `inline`,会导致字节码膨胀,因此使用 `noinline` 避免内联。 --- ## ✅ 总结对比 | 修饰符 | 是否内联 | 是否允许 lambda 中 return | 用途说明 | |--------------|----------|-----------------------------|-----------| | `inline` | ✅ 是 | ✅ 是 | 提升性能,适用于一次性使用的 lambda | | `crossinline`| ✅ 是 | ❌ 否 | 用于嵌套调用的 lambda,防止非局部 return | | `noinline` | ❌ 否 | ✅ 是 | 避免内联,适用于多次调用或需要保存的 lambda | --- ## ✅ 示例说明 ```kotlin repository.launchRequest({ apiService.getData() }, onSuccess = { // 处理成功 }, onError = { // 处理错误 }) ``` - `{ apiService.getData() }` 是 `crossinline block`,不能在里面写 `return`。 - `onSuccess`、`onError`、`onComplete` 是 `noinline`,可以被保存或多次调用。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值