当前位置: 首页 > news >正文

Kotlin的 noinline和crossinline关键字

noinline

顾名思义,noinline的意思就是不内联,这个关键字只能作用于内联高阶函数的某个函数类型的参数上,表明当前的函数参数不参与高阶函数的内联:

inline fun fun1(doSomething1: () -> Unit, noinline doSomething2: () -> Unit) {
    Log.i("tag", "1")
    doSomething1()
    doSomething2()
}
 
//调用
fun mainFun() {
    fun1({ Log.i("tag", "2") }, { Log.i("tag", "3") })
}
 
//实际编译的代码
fun mainFun() {
    Log.i("tag", "1")
    Log.i("tag", "2")
    ({Log.i("tag", "3")}).invoke()
}

但是这个关键字有什么用呢?

在kotlin中高阶函数的函数类型的参数我们可以直接当做一个函数去调用,但是函数类型的参数终究还是一个对象,既然是一个对象那么我们就可以以对象的形式去使用,就比如说作为函数返回值进行返回:

inline fun fun1(doSomething1: () -> Unit, doSomething2: () -> Unit): () -> Unit {
    Log.i("tag", "1")
    doSomething1()
    doSomething2()
    return doSomething2
    //这里编译器会提示报错,因为作为内联函数的函数类型参数,
    //它已经不能作为对象去使用了。如果不加inline关键字这里就是正确的
}

我们知道内联函数的函数类型参数是不会再创建函数对象的,也就是说它只是一个函数体而不是一个函数对象,所以它无法被当做一个对象那样作为返回值进行返回。

所以当我们在内联函数里面真的需要将一个函数类型的参数作为对象去使用时就需要noinline关键字去修饰它:

inline fun fun1(doSomething1: () -> Unit, noinline doSomething2: () -> Unit): () -> Unit {
    Log.i("tag", "1")
    doSomething1()
    doSomething2()
    return doSomething2//编译正常
}

crossinline

crossinline的含义字面上可以理解为对inline做局部加强内联

场景:

inline fun fun1(doSomething1: () -> Unit){
    Log.i("tag", "1")
    doSomething1()
}
 
//调用
fun mainFun() {
    fun1 {
        Log.i("tag", "2")
        return
//按照一般的原则,这里的return结束的应该是fun1函数体中的逻辑,就是说Log.i("tag", "3")会被执行到。
//但是fun1作为内联函数会在编译时被完全铺平,这里return结束的就是最外面mainFun函数的逻辑,Log.i("tag", "3")就不会被执行到。
    }
    Log.i("tag", "3")
}
 
//实际编译的代码
fun mainFun() {
    Log.i("tag", "1")
    Log.i("tag", "2")
    return
    Log.i("tag", "3")
}

按照一般的原则,这里的return结束的应该是fun1函数体中的逻辑,就是说Log.i("tag", "3")会被执行到。

但是fun1作为内联函数会在编译时被完全铺平,这里return结束的就是最外面mainFun函数的逻辑,Log.i("tag", "3")就不会被执行到。

那我们在函数类型参数的lambda表达式中执行的return到底结束的是当前函数还是最外层的函数完全要看fun1到底是不是内联函数,这就让我们代码敲得很难受。

为此,kotlin提出了一个新规定:lambda表达式中不允许直接使用return,除非是内联函数的函数类型参数的lambda表达式,并且它结束的是最外层的函数逻辑。同时其他场景下的lambda表达式中可以通过return@label的形式来显示指定return结束的代码作用域 。 

fun fun1(doSomething1: () -> Unit){
    Log.i("tag", "1")
    doSomething1()
}
 
fun mainFun() {
    fun1 {
        Log.i("tag", "2")
        //return//直接return在这里是不被允许的,因为fun1不是内联函数
        return@fun1//return@label的形式
    }
    Log.i("tag", "3")
}

再来看一种场景:

inline fun fun1(doSomething1: () -> Unit){
    Log.i("tag", "1")
    Runnable {
        doSomething1()//这里会编译报错
    }
}
 
//调用
fun mainFun() {
    fun1 {
        Log.i("tag", "2")
        return
    }
    Log.i("tag", "3")
}

我们在内联函数fun1中将函数类型参数doSomething1放到了子线程里面去执行,这样doSomething1和fun1就属于间接调用的关系,

那mainFun函数中的return结束的到底是Runnable子线程中的逻辑还是mainFun函数中的逻辑呢?

所以kotlin是不允许直接这样写的,但是我确实有需求要这样在内联函数中间接调用函数类型的参数怎么办?

kotlin为此又新增了一条规定:内联函数中不允许对函数类型参数的间接调用,除非该函数类型参数被crossinline关键字修饰:(这就是局部加强内联的含义)

代码:

inline fun fun1(crossinline doSomething1: () -> Unit){
    Log.i("tag", "1")
    Runnable {
        doSomething1()
    }
}
 
//调用
fun mainFun() {
    fun1 {
        Log.i("tag", "2")
        return//这里会编译报错
    }
    Log.i("tag", "3")
}

crossinline可以到达间接调用函数类型参数的目的 。

但是并没有解决“mainFun函数中的return结束的到底是Runnable子线程中的逻辑还是mainFun函数中的逻辑呢?

于是kotlin干脆在间接调用的情况下内联函数的函数类型参数的lambda表达式不允许直接使用return,即下面这两个规定不可以共存:

  1.  lambda表达式中不允许直接使用return,除非是内联函数的函数类型参数的lambda表达式,并且它结束的是最外层的函数逻辑
  2. 内联函数中不允许类似上述问题中对函数类型参数的间接调用,除非该函数类型参数被crossinline关键字修饰


最终代码:(用return@label的形式来显示指定return结束的代码作用域)

inline fun fun1(crossinline doSomething1: () -> Unit){
    Log.i("tag", "1")
    Runnable {
        doSomething1()
    }
}
 
//调用
fun mainFun() {
    fun1 {
        Log.i("tag", "2")
        return@fun1//编译正常
    }
    Log.i("tag", "3")
}

结束。

相关文章:

  • k8s的核心组件整理
  • 多阶段构建实现 Docker 加速与体积减小:含文件查看、上传及拷贝功能的 FastAPI 应用镜像构建
  • Android 接 Twitter Share ,常见问题及解决方案
  • 流畅如丝:利用requestAnimationFrame优化你的Web动画体验
  • 基于Web大学生创新服务平台(源码+lw+部署文档+讲解),源码可白嫖!
  • 摄影工作室预约管理系统基于Spring BootSSM
  • Sympy入门之微积分基本运算
  • 【中间件】Rabbit离线部署操作
  • windows单节点验证victoriametrics结合AlertManger实现告警推送webhook
  • 对接马来西亚、印度、韩国、越南等全球金融数据示例
  • 个人作品集模板!除了Figma还可以选择什么软件?
  • neo4j-如何让外部设备访问wsl中的neo4j
  • Python 类与对象概念全解析:从零到实战
  • Ubuntu上安装Docker
  • 统计哲学的频率学派和贝叶斯学派
  • Redis的大Key问题如何解决?
  • 基于单片机的农作物自动灌溉系统
  • sougou AI close
  • Milvus WeightedRanker 对比 RRF 重排机制
  • Linux信号的诞生与归宿:内核如何管理信号的生成、阻塞和递达?
  • 中国纪检监察刊文:力戒形式主义官僚主义关键是要坚持实事求是
  • 工人日报:应对“职场肥胖”,健康与减重同受关注
  • 老字号“逆生长”,上海制造的出海“蜜”钥
  • 一涉嫌开设赌场的网上在逃人员在山东威海落网
  • 阿里上季度营收增7%:淘天营收创新高,AI产品营收连续七个季度三位数增长
  • “大型翻车现场”科技满满,黄骅打造现代化港口和沿海新城典范