高阶函数非常有帮助,它们可以真正改善reusability
代码。但是,使用它们的最大问题之一是效率。Lambda表达式被编译为类(通常是匿名类),而Java中的对象创建是一项繁重的操作。通过使函数内联,我们仍然可以有效地使用高阶函数,同时保留所有好处。
这是内联函数的图片
将功能标记为时inline
,在代码编译期间,编译器将使用该功能的实际主体替换所有功能调用。同样,作为参数提供的lambda表达式将替换为其实际主体。它们不会被视为函数,而是实际的代码。
简而言之:-内联->而不是被调用,而是在编译时由函数的主体代码代替...
在Kotlin中,使用一个函数作为另一个函数(所谓的高阶函数)的参数比使用Java更自然。
但是,使用lambda有一些缺点。由于它们是匿名类(因此是对象),因此它们需要内存(甚至可能增加您应用程序的总体方法数量)。为了避免这种情况,我们可以内联我们的方法。
fun notInlined(getString: () -> String?) = println(getString())
inline fun inlined(getString: () -> String?) = println(getString())
从上面的示例中可以看出:-这两个函数做的完全相同-打印getString函数的结果。一种是内联的,一种不是。
如果要检查反编译的Java代码,您会发现方法完全相同。这是因为inline关键字是对编译器的指令,用于将代码复制到调用站点中。
但是,如果我们将任何函数类型传递给另一个函数,如下所示:
//Compile time error… Illegal usage of inline function type ftOne...
inline fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
为了解决这个问题,我们可以如下重写函数:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int, ftTwo: (Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
假设我们有一个如下所示的高阶函数:
inline fun Int.doSomething(y: Int, noinline ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/}
在这里,当只有一个lambda参数并且我们将其传递给另一个函数时,编译器将告诉我们不要使用inline关键字。因此,我们可以如下重写上述函数:
fun Int.doSomething(y: Int, ftOne: Int.(Int) -> Int) {
//passing a function type to another function
val funOne = someFunction(ftOne)
/*...*/
}
注意:-我们也必须删除关键字noinline,因为它只能用于内联函数!
假设我们有这样的功能 ->
fun intercept() {
// ...
val start = SystemClock.elapsedRealtime()
val result = doSomethingWeWantToMeasure()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
// ...}
这很好用,但是函数逻辑的实质被测量代码污染了,这使您的同事更难以处理正在发生的事情。:)
内联函数可以帮助以下代码:
fun intercept() {
// ...
val result = measure { doSomethingWeWantToMeasure() }
// ...
}
inline fun <T> measure(action: () -> T) {
val start = SystemClock.elapsedRealtime()
val result = action()
val duration = SystemClock.elapsedRealtime() - start
log(duration)
return result
}
现在,我可以专注于阅读intercept()函数的主要意图,而无需跳过测量代码行。我们还受益于可以在其他地方重用该代码的选项
内联允许您在闭包({...})中调用带有lambda参数的函数,而不是像measure(myLamda)一样传递lambda