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