dd

Scala开发教程(27): 创建新的控制结构

jerry Scala 2015年11月25日 收藏

对于支持函数作为“头等公民”的语言,你可以有效的创建新的控制结构即使该语言语法上固定的。你所要做的事创建一个方法,该方法使用函数类型作为参数。
比如: 下面为一个“双倍”的控制结构,这个“双倍”控制结构可以重复一个操作,然后返回结果。

scala> def twice (op:Double => Double, x:Double) =op(op(x))
twice: (op: Double => Double, x: Double)Double

scala> twice(_ + 1, 5)
res0: Double = 7.0

上面调用twice ,其中 _+1调用两次,也就是5调用两次+1,结果为7.
你在写代码时,如果发现某些操作需要重复多次,你就可以试着将这个重复操作写成新的控制结构,在前面我们定义过一个filesMatching函数

def filesMatching(
    matcher: (String) => Boolean) = {
    for(file <- filesHere; if matcher(file.getName))
      yield file
   }

如果我们把这个函数进一步通用化,可以定义一个通用操作如下:
打开一个资源,然后对资源进行处理,最后释放资源,你可以为这个“模式”定义一个通用的控制结构如下:

def withPrintWriter (file: File, op: PrintWriter => Unit) {
  val writer=new PrintWriter(file)
  try{
    op(writer)
  }finally{
    writer.close()
  }
}

使用上面定义,我们使用如下调用:

withPrintWriter(
   new File("date.txt"),
   writer => writer.println(new java.util.Date)
)

使用这个方法的优点在于withPrintWriter,而不是用户定义的代码,withPrintWriter可以保证文件在使用完成后被关闭,也就是不可能发生忘记关闭文件的事件。这种技术成为“租赁模式”,这是因为这种类型的控制结构,比如withPrintWriter 将一个PrintWriter 对象“租”给op操作,当这个op操作完成后,它通知不再需要租用的资源,在finally中可以保证资源被释放,而无论op是否出现异常。

这里调用语法还是使用函数通常的调用方法,使用()来列出参数,在Scala中如果你调用函数只有一个参数,你可以使用{}来替代().比如下面两种语法是等价的:

scala> println ("Hello,World")
Hello,World

scala> println { "Hello,world" }
Hello,world

上面第二种用法,使用{}替代了(),但这只适用在使用一个参数的调用情况。 前面定义withPrintWriter 函数使用了两个参数,因此不能使用{}来替代(),但如果我们使用柯里化重新定义下这个函数如下:

import scala.io._
import java.io._
def withPrintWriter (file: File)( op: PrintWriter => Unit) {
  val writer=new PrintWriter(file)
  try{
    op(writer)
  }finally{
    writer.close()
  }
}

将一个参数列表,变成两个参数列表,每个列表含一个参数,这样我们就可以使用如下语法来调用withPrintWriter

val file = new File("date.txt")
withPrintWriter(file){
  writer => writer.println(new java.util.Date)
}

第一个参数我们还是使用()(我们也可以使用{}),第二个参数我们使用{}来替代(),这样修改过的代码使得withPrintWriter 看起来和Scala内置的控制结构语法一样。

dd