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