从forEach理解一下kotlin的inline

Android 开发中有很多语法糖 其中 for Each 可以替代 for 循环 ,简洁 的语法是很常用的

tempList.forEach {
   Timber.d("print list value =>${it}")
}

在使用 for Each 相信每个开发者都会踩的一个坑就是 for Each 中的 return@forEach 无法直接退出 forEach

tempList.forEach {
   if (it == ""){
       return@forEach
   }
   Timber.d("print list value =>${it}")
}

先说个最常见的解决方案 在外层包一个 run 然后使用 return@run 退出即可

run{
   tempList.forEach {
       if (it == ""){
           return@run
       }
       Timber.d("print list value =>${it}")
   }
}

那么为什么 for Each 不能直接退出呢 这就要从 kotlin 中有个非常好用的关键字 inline 说起 它可以帮你对做了标记的函数进行内联优化。所谓内联就是,调用的函数在编译的时候会变成代码内嵌的形式

fun test(){
   testInline()
}
private inline fun testInline(){
   Timber.d("testInline")
}
//等于
fun test(){
   Timber.d("testInline")
}

kotlin 中方法也是变量 所以这样做的区别在于 不实用 inline 每次调用会多创建一个变量 在频繁的调用时 例如 for 循环中 内存的开销会变得很大

这也解释了 for Each 为什么要使用 inline

 

如果针对其中某个参数不需要 inline 可以使用 no Inline 效果如下

inline fun test1(first:()->Unit,noinline second:()->Unit){
   first()
   Timber.d("3")
   second()
}
fun main(){
   test1({
         Timber.d("1")
   },{
       Timber.d("2")
   })
}

等于

fun main(){
   Timber.d("1")
   Timber.d("3")
   ({
       Timber.d("2")
   })
}

这里面有个坑 我们前面提到 kotlin 中方法也是变量 所以在实际使用中 就可以加上 noInline 来返回该方法

inline fun test1(first:()->Unit, noinline second:()->Unit): () -> Unit {
   first()
   Timber.d("3")
   return second
}

如果不加上 no Inlie

这是因为这时实际编译结果是

fun main(){
   Timber.d("1")
   Timber.d("3")
   Timber.d("2")
   second
}

可以看到最后突兀的出现一个 second

除了 no Inline 还有个 crossInline 刚才讲的 noinline 是局部关闭内联优化 而这个 crossinline ,是局部加强内联优化

再看一下例子

inline fun test1(first:()->Unit) {
   first()
   Timber.d("2")
}
fun main(){
   test1{
       Timber.d("1")
       return
   }
}

当我在使用内联函数时在里面调用了 return 因为使用内联 方法到最后是展开的 也就是

fun main(){
   Timber.d("1")
   Timber.d("2")
   return
}

所以 他的本质是结束 mai n 函数 而不是只结束 test 1 函数

如果将 test 1 first 的调用放在主线程中

可以看到系统提示要使用 cross Inline 在使用之后 就会告诉不允许在 mai n 当中这样使用 main 当中只能 return @ test 1

所以什么时候需要 crossinline?当你需要突破内联函数的「不能间接调用参数」的限制的时候。


请使用浏览器的分享功能分享到微信等