前言
看了很多博客,才明白了内联的含义,其实最根本的就是将写在别处的代码拷贝到你现在执行的方法中,相当于在一个方法中执行,java的方法执行是需要压栈出栈的对吧,如果是两三个方法那就是两三次的压栈出栈,为了节省这个操作,提高一定的效率,kotlin就出了这么个函数。但又想想,如果是个超级大的函数,考来考去的也是很麻烦啊,所以这东西需要自己权衡吧,遵守单一职责,降低代码圈发杂度才是根本。
内联函数的理解
inline函数(内联函数)从概念上讲是编译器使用函数实现的真实代码来替换每一次的函数调用,带来的最直接的好处就是节省了函数调用的开销,而缺点就是增加了所生成字节码的尺寸。基于此,在代码量不是很大的情况下,我们是否有必要将所有的函数定义为内联?让我们分两种情况进行说明:
inline fun doSomething(action: () -> Unit) { println("Before doSomething...") action() println("After doSomething...") }
假如我们这样调用doSomething:
fun main(args: Array) { doSomething { pringln("Hello World") } }
上面的调用会被编译成:
fun main(args: Array) { println("Before doSomething...") println("Hello World") println("After doSomething...") }
从上面编译的结果可以看出,无论doSomething函数还是action参数都被内联了,很棒,那让我们换一种调用方式:
fun main(args: Array) { val action:() -> Unit = { println("Hello World") } doSomething(action) }
上面的调用会被编译成:
fun main(args: Array) { println("Before doSomething...") action() println("After doSomething...") }
doSomething函数被内联,而action参数没有被内联,这是因为以函数型变量的形式传递给doSomething的lambda在函数的调用点是不可用的,只有等到doSomething被内联后,该lambda才可以正常使用。
通过上面的例子,我们对lambda表达式何时被内联做一下简单的总结:
上面对lambda的内联时机进行了讨论,消化片刻后让我们再看最后一个例子:
inline fun doSomething(action: () -> Unit, secretAction: () -> Unit) { action() doSomethingSecret(secretAction) } fun doSomethingSecret(secretAction: () -> Unit) { }
上面的例子是否有问题?是的,编译器会抛出“Illegal usage of inline-parameter”的错误,这是因为Kotlin规定内联函数中的lambda参数只能被直接调用或者传递给另外一个内联函数,除此之外不能作为他用;那我们如果确实想要将某一个lambda传递给一个非内联函数怎么办?我们只需将上述代码这样改造即可:
inline fun doSomething(action: () -> Unit, noinline secretAction: () -> Unit) { action() doSomethingSecret(secretAction) } fun doSomethingSecret(secretAction: () -> Unit) { }
很简单,在不需要内联的lambda参数前加上noinline修饰符就可以了。
以上便是我对内联函数的全部理解,通过掌握该特性的运行机制,相信大家可以做到在正确的时机使用该特性,而非滥用或因恐惧弃而不用。