Kotlin高阶函数

此Kotlin支持多种方式来调用高阶函数,比如另一个函数、Lambda表达式、匿名函数、成员引用等。其中,Lambda表达式是最常见也是最普遍的高阶函数调用方式

1 定义高阶函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
fun plus(num1: Int, num2: Int): Int {
return num1 + num2
}
fun minus(num1: Int, num2: Int): Int {
return num1 - num2
}

fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
val result = operation(num1, num2)
return result
}

fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1, num2, ::plus)
val result2 = num1AndNum2(num1, num2, ::minus)
println("result1 is $result1")
println("result2 is $result2")
}

注意这里调用num1AndNum2()函数的方式,第三个参数使用了::plus和::minus这种写法。这是一种函数引用方式的写法,表示将plus()和minus()函数作为参数传递给num1AndNum2()函数。

上述代码如果使用Lambda表达式的写法来实现的话,代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
fun main() {
val num1 = 100
val num2 = 80
val result1 = num1AndNum2(num1, num2) { n1, n2 ->
n1 + n2
}
val result2 = num1AndNum2(num1, num2) { n1, n2 ->
n1 - n2
}
println("result1 is $result1")
println("result2 is $result2")
}
2 内联函数

内联函数的用法非常简单,只需要在定义高阶函数时加上inline关键字的声明即可,如下所示:

1
2
3
4
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int {
val result = operation(num1, num2)
return result
}

内联函数的工作原理是是Kotlin编译器会将内联函数中的代码在编译的时候自动替换到调用它的地方,这样也就不存在运行时的开销了。

3 noinline与crossinline

一个高阶函数中如果接收了两个或者更多函数类型的参数,这时我们给函数加上了inline关键字,那么Kotlin编译器会自动将所有引用的Lambda表达式全部进行内联。

只想内联其中的一个Lambda表达式,使用noinline关键字了,如下所示:

1
2
inline fun inlineTest(block1: () -> Unit, noinline block2: () -> Unit) {
}

非内联的函数类型参数可以自由地传递给其他任何函数,因为它就是一个真实的参数,而内联的函数类型参数只允许传递给另外一个内联函数,这也是它最大的局限性。另外,内联函数和非内联函数还有一个重要的区别,那就是内联函数所引用的Lambda表达式中是可以使用return关键字来进行函数返回的,而非内联函数只能进行局部返回。

在高阶函数中创建了另外的Lambda或者匿名类的实现,并且在这些实现中调用函数类型参数,此时再将高阶函数声明成内联函数,就一定会提示错误。crossinline关键字就像一个契约,它用于保证在内联函数的Lambda表达式中一定不会使用return关键字。