在函数式编程中,允许采用变量保存函数,也可以将函数作为参数值或者返回值。因此,必然存在一种函数,它以另一个函数作为参数或者返回值,这种函数叫高阶函数。
函数类型
正如上一节我们谈到的,函数也是有类型的,称为函数类型。声明函数类型,需要将函数参数类型放在一个括号中,紧接着是一个箭头和函数的返回类型,例如:
当然,同普通变量一样,函数变量也是可以初始化的
在Kotlin中,Unit类型用于表示函数不返回任何有用的值,例如:
在了解了函数类型之后,我们可以定义高阶函数了,以下定义了一个将函数作为参数的高阶函数:
函数接收一个以两个Int作为参数并且返回Int的函数,然后用这个函数求得2和3的运算结果
把函数作为返回值也许不怎么常用,但是在某些条件下还是挺方便的,例如著名的策略模式(设计模式中的一种):
利用高阶函数去除重复代码
在开发过程中我们常常需要进行多线程异步操作,当一个线程完成工作时通知另一个线程,最古老的方式是回调。
这意味着我们为了很简单的任务,需要编写大量的代码,更严重的是,如果这个任务还和其他任务有多线程协作,就会有新的回调,这将变成回调的地狱。从代码里可以看到,我们真正关心的只不过是这两个线程做了什么而已(两段代码),那么,我们有没有简化的方式呢?
当然有,因为lambda代表的就是程序的一小段代码嘛:
现在我们可以直接调用runAsync函数进行异步操作了,当然,这个封装是有问题的,它只接受无参数值并且无返回值的函数,这个在不久的将来将会被改进,如果你熟悉RxJava的话,你应该对下面这个函数不陌生:
这个函数表示了异步任务完成后主线程的工作,当然,要完全搞懂这个函数还需要一点其他的知识。
通过内联函数消除lambda带来的运行时开销
我们知道lambda表达式会编译成匿名类,而且在捕捉了外部变量后,会在调用的时候产生新的对象,那么,能不能消除这种额外开销呢?
当一个函数被声明为inline时,它的函数体时内联的,函数体将被直接替换到函数被调用的地方
例如,下面的两个函数是等价的:
事实上,内联函数repeat函数在执行时会编译为repeat2的形态,这样就避免了匿名类的创建。
那么所有的函数都可以被内联么?
在内联的时候,作为参数的lambda表达式的函数体会被直接替换到最终生成的代码中。如果lambda在某个地方被保存起来供以后使用,则lambda表达式不能被内联,比如:
显然,传入的函数参数来自其他地方,系统在编译这个类的时候都不知道传入的函数func是什么,自然不可能进行直接替换
由于内联函数是直接替换到最终的代码中,因此,它往往还可以捕获一些上下文信息,因此除了能减少匿名类的创建以外,它还有其他用途,我们将在未来谈到它。