
3.1.2 高阶函数
Kotlin的函数是“第一等公民”,函数就是对象,这是Kotlin作为函数式编程语言的重要特性。对象可以直接赋值给变量,可以作为某个函数的参数,也可以作为别的函数的返回值,那么函数也可以,如图3-1所示。

图3-1 Kotlin高阶函数类型
1.函数可以赋值给变量
请看如下示例:

上述代码中,函数被赋值给变量,其中:

等价于:
val sum: (Int, Int) -> Int = { x, y -> x + y }
在上述例子中,变量sum是函数类型,它接收两个Int类型的参数,并且返回一个Int类型的值。
在使用时,就像调用函数一样,例如:
sum(3, 5)
函数类型有以下特性:
(1)所有函数类型都有一个圆括号括起来的参数类型列表以及一个返回类型:(A, B) -> C表示接收类型分别为A与B的两个参数并返回一个C类型的值。参数类型列表可以为空,如() -> A。Unit返回类型不可省略。
(2)函数类型可以有一个额外的接收者类型,它在表示法中的点之前指定:类型A.(B) -> C表示可以在A的接收者对象上以一个B类型参数来调用,并返回一个C类型值的函数。带有接收者的函数字面值通常与这些类型一起使用。
(3)挂起函数属于特殊种类的函数类型,它的表示法中有一个suspend修饰符,例如suspend()-> Unit或者suspend A.(B) -> C。
其中,第二点和第三点特性分别在第8章和第11章详细说明。
回过头再来看sum这个函数类型,它本质上实现了kotlin.jvm.functions.Function2接口。

那么:
println(sum(3, 5)) //8
应该等价于:
println(sum.invoke(3, 5)) //8
事实上也是如此。这里可以省略invoke,是因为运算符重载了,在9.1节会详细说明。
函数类型的实例化如图3-2所示。

图3-2 函数类型的实例化
函数赋值给变量之后,编译器能够根据足够的信息推断出变量的函数类型。
以最初的例子为例:
val sum = { x: Int, y: Int -> x + y }
编译器能够推断出sum的类型是(Int, Int) -> Int。
另外,(A, B) -> C类型的值可以传给A.(B) -> C类型,反之亦可。
2.函数可以作为其他函数的参数
例如,下面是使用高阶函数实现求和、求平方和、求立方和的例子。term是一个函数类型的参数。

由于sum函数中的函数类型参数在最后,在使用时可以进一步简化,将它提到最外面。

还可以进一步简化代码,因为term的类型是(Int) -> Int,它只有一个参数,可以忽略声明函数参数(以及忽略->),使用it来替代参数。

3.函数可以作为其他函数的返回值
对上述代码进行修改,新增一个sum函数,它将函数作为返回值。

调用新增的sum函数,它返回的是(Int, Int) -> Int。把返回的函数赋值给变量之后,该变量需要传递两个Int类型的参数才能使用。
var identityFunction = sum("identity") println(identityFunction(1,10)) //55