Kotlin 内联函数
在 Kotlin 中,高阶函数或 lambda 表达式都存储为对象,因此函数对象和类的内存分配和虚拟调用可能会引入运行时开销。有时我们可以通过内联 lambda 表达式来消除内存开销。为了减少此类高阶函数或 lambda 表达式的内存开销,我们可以使用inline关键字,它最终要求编译器不分配内存,只需在调用处复制该函数的内联代码即可。例子:
Kotlin
fun higherfunc( str : String, mycall :(String)-> Unit) {
// inovkes the print() by passing the string str
mycall(str)
}
// main function
fun main(args: Array) {
print("GeeskforGeeks: ")
higherfunc("A Computer Science portal for Geeks",::print)
}
Kotlin
inline fun higherfunc( str : String, mycall :(String)-> Unit){
// inovkes the print() by passing the string str
mycall(str)
}
// main function
fun main(args: Array) {
print("GeeskforGeeks: ")
higherfunc("A Computer Science portal for Geeks",::print)
}
Kotlin
var lambda = { println("Lambda expression")
return } // normally lambda expression does not allow return
// statement, so gives compile time error
fun main(args: Array) {
lambda()
}
Kotlin
var lambda1 = { println("Lambda expression")}
fun main(args: Array) {
lambda1()
}
Kotlin
fun main(args: Array){
println("Main function starts")
inlinedFunc({ println("Lambda expression 1")
return }, // inlined function allow return
// statement in lambda expression
// so, does not give compile time error
{ println("Lambda expression 2")} )
println("Main function ends")
}
// inlined function
inline fun inlinedFunc( lmbd1: () -> Unit, lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
Kotlin
fun main(args: Array){
println("Main function starts")
inlinedfunc({ println("Lambda expression 1")
return }, // It gives compiler error
{ println("Lambda expression 2")} )
println("Main function ends")
}
inline fun inlinedfunc( crossinline lmbd1: () -> Unit, lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
Kotlin
fun main(args: Array){
println("Main function starts")
inlinedFunc({ println("Lambda expression 1")
return }, // It does not compiler time error
{ println("Lambda expression 2")
return } ) // It gives compiler error
println("Main function ends")
}
inline fun inlinedFunc( lmbd1: () -> Unit, noinline lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
Kotlin
fun main(args: Array) {
genericFunc()
}
inline fun genericFunc() {
print(T::class)
}
Kotlin
fun main(args: Array) {
print(flag)
}
fun foo(i: Int ): Int{
var a = i
return a
}
inline var flag : Boolean
get() = foo(10 ) == 10
set(flag) {flag}
字节码:与Java一样,Kotlin 也是独立于平台的语言,因此它首先转换为字节码。我们可以通过Tools -> Kotlin -> Show Kotlin Bytecode获取字节码。然后,反编译得到这个字节码。
在上面的字节码中,主要关注的部分是:
mycall.invoke(str)
mycall通过将字符串作为参数传递来调用打印函数。在调用 print() 时,它会创建一个额外的调用并增加内存开销。
它像
mycall(new Function() {
@Override
public void invoke() {
//println statement is called here.
}
});
如果我们调用大量函数作为参数,它们中的每一个都会增加方法计数,那么对内存和性能有很大的影响。
在上面的程序中,内联关键字会做什么?
科特林
inline fun higherfunc( str : String, mycall :(String)-> Unit){
// inovkes the print() by passing the string str
mycall(str)
}
// main function
fun main(args: Array) {
print("GeeskforGeeks: ")
higherfunc("A Computer Science portal for Geeks",::print)
}
字节码:
在inline关键字的帮助下, println lambda 表达式以 System.out.println 的形式复制到主函数中,无需进一步调用。
非本地控制流
在 Kotlin 中,如果我们想从 lambda 表达式返回,那么 Kotlin 编译器不允许我们这样做。借助 inline 关键字,我们可以从 lambda 表达式本身返回并退出调用内联函数的函数。
Kotlin 在 Lambda 表达式中使用 return 的程序:
科特林
var lambda = { println("Lambda expression")
return } // normally lambda expression does not allow return
// statement, so gives compile time error
fun main(args: Array) {
lambda()
}
输出:
Error:(4, 5) Kotlin: 'return' is not allowed here
通常它不允许从 lambda 返回并给出错误。
科特林
var lambda1 = { println("Lambda expression")}
fun main(args: Array) {
lambda1()
}
输出:
Lambda expression
通常没有它可以正常工作并打印声明。
Kotlin 在 Lambda 中使用 return 作为参数传递给内联函数的程序:
科特林
fun main(args: Array){
println("Main function starts")
inlinedFunc({ println("Lambda expression 1")
return }, // inlined function allow return
// statement in lambda expression
// so, does not give compile time error
{ println("Lambda expression 2")} )
println("Main function ends")
}
// inlined function
inline fun inlinedFunc( lmbd1: () -> Unit, lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
输出:
Main function starts
Lambda expression 1
说明:在这里,我们将两个 lambda 表达式作为参数传递给inlinedFunc()函数。在从 main 调用内联函数时,我们将两者都传递给它的参数。在内联函数中, lmbd1()调用了第一个表达式,并且 return 关键字强制 lambda 表达式本身和调用它的主函数退出。
跨线关键字
在上面的程序中,lambda 中的 return 退出了内联函数以及它的封闭函数。因此,要停止从 lambda 表达式返回,我们可以使用交叉线对其进行标记。如果在 Lambda 表达式中看到任何 return 语句,它将引发编译器错误。
例子:
科特林
fun main(args: Array){
println("Main function starts")
inlinedfunc({ println("Lambda expression 1")
return }, // It gives compiler error
{ println("Lambda expression 2")} )
println("Main function ends")
}
inline fun inlinedfunc( crossinline lmbd1: () -> Unit, lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
输出:
Error:(6, 9) Kotlin: 'return' is not allowed here
内线
在 Kotlin 中,如果我们只想将传递给内联函数的一些 lambda 表达式内联,我们可以使用 noinline 修饰符标记一些函数参数。
科特林
fun main(args: Array){
println("Main function starts")
inlinedFunc({ println("Lambda expression 1")
return }, // It does not compiler time error
{ println("Lambda expression 2")
return } ) // It gives compiler error
println("Main function ends")
}
inline fun inlinedFunc( lmbd1: () -> Unit, noinline lmbd2: () -> Unit ) {
lmbd1()
lmbd2()
}
输出:
Error:(11, 13) Kotlin: 'return' is not allowed here
具体类型参数
有时我们需要访问调用过程中传递的参数类型。我们必须在函数调用时简单地传递参数,我们可以使用 reified 修饰符检索参数的类型。
科特林
fun main(args: Array) {
genericFunc()
}
inline fun genericFunc() {
print(T::class)
}
输出:
class kotlin.String
内联属性
内联函数将代码复制到调用位置,类似的 inline 关键字将内联属性访问器方法复制到调用位置。 inline 修饰符可用于没有支持字段的属性的访问器。
科特林
fun main(args: Array) {
print(flag)
}
fun foo(i: Int ): Int{
var a = i
return a
}
inline var flag : Boolean
get() = foo(10 ) == 10
set(flag) {flag}
输出:
true