高阶函数
高阶函数:以其它函数做参数的函数。
高阶函数的好处之一:可以让你创造抽象控制从而减少代码重复。
import java.io.File
object Test{
private def filesHere = new File(".").listFiles //获得当前目录下的所有文件名
def filesMatching(query:String,matcher:(String,String)=>Boolean):Unit = {//①
for(file <- filesHere; if matcher(file.getName,query))//② //遍历目录下所有文件,如果某个文件的文件名符合matcher函数返回真的条件,那么就返回该文件
yield file
}
def filesEnding(query:String) = {//③ 查询以query结尾的文件名
filesMatching(query,_.endsWith(_))//④
}
def filesContaining(query:String) = { //查询包含query的文件名
filesMatching(query,_.contains(_))
}
def filesRegex(query:String) = { // 查询符合query 正则的文件名
filesMatching(quey,_.matches(_))//⑤
}
}
/*
①:filesMatching 方法有两个参数,一个String类型,参数名为query,一个为函数类型,参数名为matcher。
(String,String) => Boolean 中 “=>” 说明这是一个函数类型。该函数类型接受两个字符串参数,并且返回一个布尔值。这是一个类型就像String,Int类型一样,它只是规定一个“要求” ,而它的字面量要去具体实现它的要求。像字符串类型,要求它的字面量是一个任意的字符串。Int类型要求它的字面量是一个任意的数值。这个函数类型要求它的字面量是一个任意的 接受两个字符串参数 并且返回一个布尔值的函数字面量(也叫函数值)
②:match(file.getName,query) 这条语句,定义了如何使用函数类型,如何传参,也就是说,给出了对具体的 函数字面量的使用方法,以及传参的方式。
③:定义了一个方法————文件名以某些字符串为结尾的查询方法。它的函数体内部调用“实例化了”的filesMatching方法。具体来说,就是 “._endsWith(_)” 这个短小的方法/函数字面量 即为 上文 matcher 类型的具体实现 。从而获取以 query 为结尾的文件。下面三个类似原理。
④:_.endsWith(_) 这个函数字面量,用到了 “_” 占位符。当一条语句中出现多个“_”时,它并不表示而且不允许,一个参数(这里的参数只是这个小小的字面量的参数)的重复出现,而是,一个"_"表示一个不同的参数。也就是说前后两个是而且必须“代指”着不同的东西。根据上面matcher中的使用方法定义 if matcher(file.getName,query),我们可以知道第一个"_" 代表file.getName 即文件名,后一个"_"表示 query,所以,_.endsWith(_)的真是意思是
(file.geName).endsWith(query)。
⑤:通过观察发现可以 filesEnding filesContaining filesRegex三个方法,接收了一个query参数作为查询条件,然后都把query传给了各自内部的 filesMatching()函数,然而,filesMatching把query当作了第一个参数,然后就没有然后了,它没有对query参数做任何操作,除了将其又作为参数传给filesMatching的第二个参数,matcher类型的函数字面量,做第二个参数。这个query多次传播并没有意义,而且,filesMatching作为一个被本地函数,它本就能够访问上面三个方法中的各种参数。所以,这就意味着,三个方法,再次将query传递给filesMatching函数是没必要的。所以,matcher的三个具体实现可以进行修改,舍弃query方法。又然而它们是matcher函数类型的字面量,所以需要从源头上进行修改,也就是说,对matcher类型进行修改才行。所以matcher修改为如下类型:
matcher: String => Boolean 即接受一个字符串参数,返回一个布尔值。
..... if matcher(file.getName) .....
所以下面的三个本地函数也就可以相应的修改为
filesMatcher(_.endsWith(query)),filesMatcher(_.contains(query)).当然第一个“_”还是代表文件名。
⑥:在 ⑤未修改之前,_.endsWith(_)虽然有两个参数,但是他们都是通过matcher(file.getName,query)两个参数进行了绑定。然而filesMatcher(_.endsWith(query))修改后,第一个“_”依旧通过matcher(file.getName) 来后去了filename的帮定。然后query并没有获取传参,没办法绑定。因而成了自由变量,但是通过本地函数所处上下文,它并不是纯粹的自由变量了,它是通过捕获filesEnding(query) 中的参数query来获得绑定的。因此 filesMatcher(_.endsWith(query)) 是个闭包。
*/