这个例子中展示的函数文本使用了前一章中介绍的占位符语法,对你来说可能感觉不是非常自然。因此,以下阐明例子里是如何使用占位符的。用在filesEnding方法里的函数文本_.endsWith(_),与下面的是一回事:
(fileName: String, query: String) => fileName.endsWith(query) |
原因是filesMatching带一个函数,这个函数需要两个String参数,不过你不需要指定参数类型。因此,你也可以写成(fileName, query) => fileName.endsWith(query)。由于第一个参数,fileName,在方法体中被第一个使用,第二个参数,query,第二个使用,你也可以使用占位符语法:_.endsWith(_)。第一个下划线是第一个参数,文件名的占位符,第二个下划线是第二个参数,查询字串的占位符。
代码已经被简化了,但它实际还能更短。注意到query传递给了filesMatching,但filesMatching没有用查询做任何事只是把它传回给传入的matcher函数。这个传来传去的过程不是必需的,因为调用者在前面就已经知道了query的内容。你可以同样从filesMatching和matcher中简单地去除query参数,因此简化后的代码如展示在代码9.1中那样。
|
这个例子演示了函数作为第一类值帮助你减少代码重复的方式,如果没有它们这将变得很困难。比方说在Java里,你可以创建包括带一个String并返回Boolean的方法的接口,然后创建并传递实现这个接口的匿名内部类实例给filesMatching。尽管这个方式能去除你尝试简化掉的代码重复,但同时它增加了许多乃至更多的新代码。因此好处就不值这个开销了,于是你或许就安于重复代码的现状了。
再者,这个例子还演示了闭包是如何能帮助你减少代码重复的。前面一个例子里用到的函数文本,如_.endsWith(_)和_.contains(_),都是在运行期实例化成函数值而不是闭包,因为它们没有捕获任何自由变量。举例来说表达式_.endsWith(_)里用的两个变量,都是用下划线代表的,也就是说它们都是从传递给函数的参数获得的。因此,_.endsWith(_)使用了两个绑定变量,而不是自由变量。相对的,最近的例子里面用到的函数文本_.endsWith(query),包含一个绑定变量,下划线代表的参数,和一个名为query的自由变量。仅仅因为Scala支持闭包才使得你可以在最近的这个例子里从filesMatching中去掉query参数,从而更进一步简化了代码。