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

jerry Scala 2015年11月25日 收藏

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

  1. scala> def twice (op:Double => Double, x:Double) =op(op(x))
  2. twice: (op: Double => Double, x: Double)Double
  3.  
  4. scala> twice(_ + 1, 5)
  5. res0: Double = 7.0
  6.  

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

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

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

  1. def withPrintWriter (file: File, op: PrintWriter => Unit) {
  2. val writer=new PrintWriter(file)
  3. try{
  4. op(writer)
  5. }finally{
  6. writer.close()
  7. }
  8. }

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

  1. withPrintWriter(
  2. new File("date.txt"),
  3. writer => writer.println(new java.util.Date)
  4. )
  5.  

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

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

  1. scala> println ("Hello,World")
  2. Hello,World
  3.  
  4. scala> println { "Hello,world" }
  5. Hello,world
  6.  

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

  1. import scala.io._
  2. import java.io._
  3. def withPrintWriter (file: File)( op: PrintWriter => Unit) {
  4. val writer=new PrintWriter(file)
  5. try{
  6. op(writer)
  7. }finally{
  8. writer.close()
  9. }
  10. }
  11.  

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

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

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