抽象控制之编写新的控制结构

在拥有头等函数的语言中,即使语言的语法是固定的,你也可以有效地制作新的控制结构。所以你需要做的就是创建带函数做参数的方法。例如,下面是“双倍”控制结构,能够重复一个操作两次并返回结果:

package scala
object ScalaTest2 {
    def main(args : Array[String]) : Unit = {
        println(twice(_ + 2,6))
    }
    //自定义的新的控制结构
    def twice(op:Double => Double,x:Double) = op(op(x))
}

这个例子里op的类型是Double => Double,就是说它是带一个Double做参数并返回另一个Double的函数。任何时候,当你发现你的代码中多个地方有重复的控制模式的,就应该考虑把它实现为一个新的控制结构。

另例,打开一个资源,对它进行操作,然后关闭资源。我们使用了如下的方法将其捕获并放入控制抽象:

package scala

import java.io.PrintWriter
import java.io.File

object ScalaTest2 {
    def main(args : Array[String]) : Unit = {
        withPrintWriter(new File("D:/data.txt"), _.println(new java.util.Date))
    }
    def withPrintWriter(file:File,op:PrintWriter => Unit){
        val writer = new PrintWriter(file);
        try{
            op(writer)
        }finally{
            writer.close()
        }
    }
}

由于withPrintWriter并非用户代码,确认文件在结尾被关闭。因此忘记关闭文件是不可能的。这个技巧被称为借贷模式(loan pattern),因为控制抽象函数(withPrintWriter)打开了资源并“贷出”给函数。例如,前面例子里的withPrintWriter把PrintWriter借给函数op。当函数完成的时候,它发出信号说明它不再需要“借”的资源。于是资源,被关闭在finally块中,以确信其确实被关闭,而忽略函数是正常结束返回还是抛出了异常。

让客户代码看上去更像内建控制结构的一种方式是使用花括号代替小括号包围参数列表。Scala的任何方法调用,如果你确实只传入一个参数,就能可选地使用花括号替代小括号包围参数。如下例:


替换为花括号

这个例子里,你使用了花括号替代小括号包围println的参数。然而,这个花括号技巧仅在你传入一个参数时有效

在传入一个参数时,可以用花括号替代小括号的机制,其目的是让客户程序员能写出包围在花括号内的函数字面量。这可以让方法调用感觉更像控制抽象。以前面例子里定义的withPrintWriter方法举例。withPrintWriter带了两个参数,因此你不能使用花括号。虽然如此,因为传递给withPrintWriter的函数是列表的最后一个参数,你可以使用柯里化把第一个参数File拖入分离的参数列表。这将使函数仅剩下列表的第二个参数作为唯一的参数。有了上述的定义,你就可以用更赏心悦目的语法格式调用这个方法,代码如下:

package scala

import java.io.PrintWriter
import java.io.File

object ScalaTest2 {
    def main(args : Array[String]) : Unit = {
        withPrintWriter(new File("D:/data.txt")){
            _.println(new java.util.Date)
        }
    }
    def withPrintWriter(file:File)(op:PrintWriter => Unit){
        val writer = new PrintWriter(file);
        try{
            op(writer)
        }finally{
            writer.close()
        }
    }
}

在这个例子里,第一个参数列表包含了一个File参数,被写成包围在小括号中。第二个参数列表包含了一个函数参数,被包围在花括号中。

你可能感兴趣的:(scala)