Unit 相当于 java 中 void
1.kotlin 为啥整个内联函数?
在 kotlin 高阶函数的编译中:使用的 lambda 表达式在底层会被替换为 匿名类, 每次调用 lambda 表达式都会创建一个匿名类对象,增加内存和性能的开销。
fun num1AndNum2OnInline(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
fun main() {
num1AndNum2OnInline(2, 3) { a, b ->
a + b
}
}
kotlin 编译器在编译时会把高阶函数的lambda 表达式编译成内部类如下
public static int num1AndNum2OnInline(int num1,int num2,Function operation){
int result = (int)operation.invoke(num1,num2)
return result;
}
public static void main(){
//lambda 表达式会被编译为 匿名类
num1AndNum2OnInline(2, 3, new Function (){
@Override
public Integer invoke(int n1,int n1){
return n1+n2;
}
});
}
2. 内涵函数
kotlin 通过内联函数解决lambda表达式创建匿名类的问题
2.1 inline 关键字
定义高阶函数时加上 inline 关键字即可。
//内联函数
//定义高阶函数时,加上 inline 关键字,就是一个内联函数
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int) :Int{
return operation(num1,num2)
}
2.2 内联函数的作用
Kotlin 编译器会将内联函数中的代码在编译时自动替换到调用它位置,不在通过匿名类的方式实现
//内联函数
//定义高阶函数时,加上 inline 关键字,就是一个内联函数
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
fun num1AndNum2NoInline(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
fun main() {
var result = num1AndNum2(2, 3) { a, b ->
a + b
}
}
在使用内联函数后,kotlin 编译器会将 内联函数的代码替换到调用的位置:如下
//编译后如下
fun main() {
//将lambda 表达式中的代码替换到函数调用的位置
var result = 2+3
}
2.3 内联函数和普通函数的区别
- 内联函数所引用的 lambda 表达式中可以使用 return 进行函数返回;内联函数的lambda 可以直接使用 return
- 普通函数引用的 lambda 表达式只能局部返回 只是返回 lambda 表达式;普通函数的lambda 表达式中不能直接 使用 return,可以使用 return@xxx实现局部返回
测试代码如下
fun main() {
//普通函数和 内联函数 return 的区别
noInlineFun("普通函数 的 return "){
println("普通 lambda 函数体")
// 只是 lambda 局部返回,
return@noInlineFun // 普通函数
println("普通 lambda 函数体 end ")
}
println("-----")
inlineFun("内联函数 的 return "){
println("内联 lambda 函数体")
//调用 inlineFun()函数的 函数都返回了,后面的代码都不在执行
return
}
println("Done")
}
fun noInlineFun(str:String ,block :(String)->Unit){
println("noLineFun start str= $str")
block(str)
println("noLineFun end str= $str")
}
inline fun inlineFun(str:String ,block :(String)->Unit){
println("inlineFun start str= $str")
block(str)
println("inlineFun end str= $str")
}
//注意 noLineFun end 输出了
noLineFun start str= 普通函数 的 return
普通 lambda 函数体
noLineFun end str= 普通函数 的 return
-----
inlineFun start str= 内联函数 的 return
内联 lambda 函数体
Process finished with exit code 0
3.noinline
如果 内联函数有两个函数类型的入参,其中一个不想内联,可以使用 oninline 关键字修饰,取消内联。 代码如下:
inline fun moreParma(block: (String) -> Unit, noinline block1: (String) -> Unit) {
}
//FuncType 是先定义好的函数类型
inline fun moreParma(block: (String) -> Unit, noinline block1: FuncType) {
}
4.crossinline
使用场景:内联高阶函数中的函数类型参数,被用在lambda表达式中 如:
//内联函数 inlineFunCrossInline2() 中的函数类型参数 block 被用在 Runnable {} 中
inline fun inlineFunCrossInline2( crossinline block:()->String){
var run = Runnable {
block()
}
}
//内联函数 inlineFunCrossInline() 中的函数类型参数 block 被用在 processFunction {} 中
inline fun inlineFunCrossInline(str: String, crossinline block: FuncType, block2: FuncType) {
println(str)
//processFunction 是一个普通的高阶函数函数,接收一个函数类型的参数
var v = processFunction {
var a = block(1)
a
}
//inlineProcessFunction 是内联函数
var v2 = inlineProcessFunction {
var a = block2(1)
a
}
}
//processFunction 函数接受 FunType 类型的参数
fun processFunction(func: (Int) -> Int) {
// 在这里可以使用传递进来的函数 func
println(func(3))
}
普通的高阶函数中lambda表达式中不可以使用return,crossinline关键字像一个契约一样保证 lambda表达式中不会使用retrun。
上面的代码页证明了,如果是 内联函数 inlineProcessFunction 中调用 函数入参,则不需要 使用 crossinline 关键字。
5.定义函数类型
通过关键 typealias 声明一个 函数类型,在其他函数的入参中可以直接使用
//定义了FuncType 这样一个函数类型
typealias FuncType = (Int) -> Int
//processFunction 函数接受 FunType 类型的参数
fun processFunction(func: (Int) -> Int) {
// 在这里可以使用传递进来的函数 func
println(func(3))
}
//processFunction 函数接受 FunType 类型的参数
inline fun inlineProcessFunction(func: (Int) -> Int) {
// 在这里可以使用传递进来的函数 func
println(func(3))
}
fun myFunction(x: Int): Int {
return x * 2
}
6.下面是 inline ,noinline ,reture ,crossinLine 完整代码
//内联函数
//定义高阶函数时,加上 inline 关键字,就是一个内联函数
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
//普通高阶函数
fun num1AndNum2OnInline(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
return operation(num1, num2)
}
fun main() {
var sum = num1AndNum2OnInline(2, 3) { a, b ->
a + b
}
var sum2 = num1AndNum2(2, 3) { a, b ->
a + b
}
//传入 函数类型
processFunction(::myFunction)
//crossInline
inlineFunCrossInline("crossInline", { a ->
var value = a * 2
println("第一个lambda =$value")
value
}) { a ->
var value = a * 4
println("第一个lambda =$value")
value
}
//普通函数和 内联函数 return 的区别
//普通函数 return
noInlineFun("普通函数 的 return ") {
println("普通 lambda 函数体")
// 只是 noInlineFun() 返回,
return@noInlineFun
println("普通 lambda 函数体 end ")
}
println("-----")
//内联函数
inlineFun("内联函数 的 return ") {
println("内联 lambda 函数体")
//调用 inlineFun()函数的 函数都返回了,后面的代码都不在执行
return
}
println("Done")
}
//定义了FuncType 这样一个函数类型
typealias FuncType = (Int) -> Int
//processFunction 函数接受 FunType 类型的参数
fun processFunction(func: (Int) -> Int) {
// 在这里可以使用传递进来的函数 func
println(func(3))
}
//processFunction 函数接受 FunType 类型的参数
inline fun inlineProcessFunction(func: (Int) -> Int) {
// 在这里可以使用传递进来的函数 func
println(func(3))
}
fun myFunction(x: Int): Int {
return x * 2
}
fun noInlineFun(str: String, block: (String) -> Unit) {
println("noLineFun start str= $str")
block(str)
println("noLineFun end str= $str")
}
inline fun inlineFun(str: String, block: (String) -> Unit) {
println("inlineFun start str= $str")
block(str)
println("inlineFun end str= $str")
}
// 内联函数 多个函数入参 使用 noinline 取消内联
inline fun moreParma(block: (String) -> Unit, noinline block1: (String) -> Unit) {
}
//FuncType 是先定义好的函数类型
inline fun moreParma(block: (String) -> Unit, noinline block1: FuncType) {
}
inline fun inlineFunCrossInline(str: String, crossinline block: FuncType, block2: FuncType) {
println(str)
// processFunction 普通高阶函数
var v = processFunction {
var a = block(1)
a
}
//inlineProcessFunction 是内联函数
var v2 = inlineProcessFunction {
var a = block2(1)
a
}
}
inline fun inlineFunCrossInline2(crossinline block: () -> String) {
var run = Runnable {
block()
}
}