Kotlin内联函数入门

6 篇文章 1 订阅
1 篇文章 0 订阅
1.什么是内联函数

使用高阶函数虽然不需要显示的声明对象,但在编译的时候每个入参的函数都会被编译成一个Function对象,这个过程(内存申请,函数出入栈等)会带来一定的性能开销。

使用内联函数可以有效的消除这类的开销。内联函数是使用inline关键字声明的函数,在编译时,内联函数不会为参数创建一个函数对象,而是会将实现拷贝到调用的地方。

考虑如下代码:

 fun main(vararg args:String) {
    for (i in 0 until 10){
        sum(i,i+1){
            println(it * i)
        }
    }
}

  private fun sum(a:Int,b:Int,call:(Int)->Unit){
    call(a+b)
}
    

反编译后的Java代码:

   public static final void main(@NotNull String... args) {
      final int i = 0;
      for(byte var2 = 10; i < var2; ++i) {
         sum(i, i + 1, (Function1)(new Function1() {
         
            public Object invoke(Object var1) {
               this.invoke(((Number)var1).intValue());
               return Unit.INSTANCE;
            }

            public final void invoke(int it) {
               int var2 = it * i;
               System.out.println(var2);
            }
         }));
      }

   }

   private static final void sum(int a, int b, Function1 call) {
      call.invoke(a + b);
   }

sum是一个非内联函数,上述代码创建了10个Function1对象,将sum函数声明为inline后:

private inline fun sum(a:Int,b:Int,call:(Int)->Unit){
    call(a+b)
}

再进行反编译:

  public static final void main(@NotNull String... args) {
  
      int i = 0;
      for(byte var2 = 10; i < var2; ++i) {
         int b$iv = i + 1;
         int it = i + b$iv;
         int var7 = it * i;
         System.out.println(var7);
      }

   }

   private static final void sum(int a, int b, Function1 call) {
      call.invoke(a + b);
   }

可以看到,main函数里面并没有创建Function1对象,甚至sum函数都没有被调用到,只是将sum的实现过程拷贝到了调用处。很明显的,在这种场景下使用内联函数能够更好的提升程序的性能。

内联函数也有一定的局限性,如果函数体实现太复杂,,那么每个调用的地方都会拷贝一大份代码,这样会增加程序的体积。所以inline关键字一般用在满足以下几种情况的函数中:

  • 参数中带有lanbda函数的高阶函数
  • 函数体实现简单,代码量不多
  • 可能会被多次调用
2.内联函数的扩展

2.1 禁用内联

1.如果inline函数中有多个lambda表达式参数,那么可以用 noinline 修饰符标记不希望内联的函数参数:

inline fun foo(inlined: () -> Unit, noinline notInlined: () -> Unit) { }

2.2 禁止非局部return

2.内联函数入参的lambda表达式是允许“非局部return”的,什么是“非局部retuen”?
举个例子:

fun main(vararg args:String){
    println("before call testReturn")
    testReturn {
        return
    }
    println("after call testReturn")
}


private inline fun testReturn(f:()->Unit){
    f()
}

//上面的代码输出结果是:
//before call testReturn

上面的代码不难理解,因为内联后函数体被拷贝到了调用处,所以return并不是返回到局部的“testReturn”,而是最外层的main函数,这种情况就叫“非局部return”。大多数情况下,我们都是针对lambda表达式使用局部的return,使用crossinline可以禁止这种情况的出现:

fun main(vararg args:String){
    println("before call testReturn")
    testReturn {
        //return  无法编译通过,禁止使用非局部返回
        return@testReturn   //编译通过,使用@label显示声明局部返回
    }
    println("after call testReturn")
}


private inline fun testReturn(crossinline f:()->Unit){
    f()
}

//上面的代码输出结果是:
//before call testReturn
//after call testReturn

更多安卓知识体系,请关注公众号:
三分钟Code

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值