函数是对象

Scala 中的函数也是对象,所以将函数当做对象传递、把它们存入变量、从其他函数返回函数都是可能的。能够像操作变量一样的操作函数这点是函数式编程这一非常有趣的程序设计思想的基石之一。

为何把函数当做变量一样的操作会很有用呢,让我们考虑一个定时函数,功能是每秒执行一些动作。我们要怎么将这动作传给它?最直接的便是将这动作视为函数传入。应该有不少程序员对这种简单传递函数的行为很熟悉:通常在用户界面相关的程序上,用来注册一些当事件发生时被调用的回调函数。

在接下来的程序中,定时函数叫做oncePerSecond ,它接受一个回调函数做参数。该函数的类型被写作() => Unit ,这个类型便是所有无对象且无返回值函数的类型(Unit 这个类型就像是 C/C++ 的void )。此程序的主函数只是调用定时函数并带入回呼函数,回呼函数输出一句话到终端上。也就是说这个程序会不断的每秒输出一次 “time flies like an arrow”。

  1. object Timer {
  2. def oncePerSecond(callback: () => Unit) {
  3. while (true) { callback(); Thread sleep 1000 }
  4. }
  5. def timeFlies() {
  6. println("time flies like an arrow...")
  7. }
  8. def main(args: Array[String]) {
  9. oncePerSecond(timeFlies)
  10. }
  11. }

值得注意的是,在打印字符串时,我们使用的是 Scala 预定义的方法println,而不是System.out 中的。

匿名函数

这程序还有改进空间。第一点,函数timeFlies 只是为了能够被传递进oncePerSecond 而定义的。赋予一个只被使用一次的函数名字似乎是没有必要的,最好能够在传入oncePerSecond 时构造出这个函数。Scala 可以借由匿名函数来达到这点。利用匿名函数的改进版本程序如下:

  1. object TimerAnonymous {
  2. def oncePerSecond(callback: () => Unit) {
  3. while (true) { callback(); Thread sleep 1000 }
  4. }
  5. def main(args: Array[String]) {
  6. oncePerSecond(() =>
  7. println("time flies like an arrow..."))
  8. }
  9. }

这例子中的右箭头=> 告诉我们有一个匿名函数,右箭头将函数对象跟函数内容分开。这个例子中,在箭头左边那组空的括号告诉我们对象列是空的。函数内容则是跟先前的timeFlies 里一样。