kotlin 内联函数 inline

发布时间 2023-11-12 23:25:50作者: LCAC

一、当函数被声明为内联函数(函数的前缀增加inline),那么函数体会被直接替换到函数被声明的地方,而不是被正常的调用。如下的代码

inline fun synchronized(lock: Lock, action: () -> Unit) {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

fun foo(l: Lock) {
    println("before sync")
    synchronized(l) { // 这里的函数会被替换成synchronized的代码
        println("Action")
    }
    println("after sync")
}

咱们可以看转化成java的foo函数(这里把一些无关的判断去掉)

   public static final void foo(@NotNull Lock l) {
      System.out.println("before sync");
      l.lock();
      try {
         int var2 = false;
         System.out.println("Action");
      } finally {
         l.unlock();
      }
      System.out.println("after sync");
   }

如上所述,直接将synchronized 替换到了foo本地

 

二、当inline函数赋值给临时变量,那么该临时变量不再具有inline的特性

    val l = ReentrantLock()
    val syn = ::synchronized
    syn(l) {
        println("test")
    }

如上是kotlin的先赋值给临时变量的操作,对应的java解码是

      ReentrantLock l = new ReentrantLock();
      KFunction syn = (KFunction)null.INSTANCE;
      ((Function2)syn).invoke(l, null.INSTANCE);

如上,调用通用函数的调用invoke的方式

具体的解释是:synchronized被临时变量保存起来,以便后面的使用。 官方语言:lambda表达式的代码将不能被内联,因为必须要有一个包含这些代码的对象存在

 

三、关于inline函数的传递

正常参数如果被直接调用或者作为参数传递给另外一个inline函数,该参数是可以被内联。

如一中所述:lambda默认是inline函数,所以在传入synchronized的时候也被当作内联函数继续被解析

当禁止传入的函数也被内联,则可以对该函数参数使用noinline

inline fun synchronized(lock: Lock, noinline action: () -> Unit) {
    lock.lock()
    try {
        return action()
    } finally {
        lock.unlock()
    }
}

// 则对应的foo函数的代码则为
   public static final void foo(@NotNull Lock l) {
      System.out.println("before sync");
      Function0 action$iv = (Function0)null.INSTANCE;
      l.lock();
      try {
         action$iv.invoke(); // 这里使用的是函数的调用
      } finally {
         l.unlock();
      }
      System.out.println("after sync");
   }

如上所述,使用的是invoke,而不是inline特性的替换

 

 四、使用inline的时候注意函数不宜太过复杂或者太长,因为会被替换到本地从而增加了字节码的长度。