scala-- 高阶函数

高阶函数

高阶函数:以其它函数做参数的函数。

高阶函数的好处之一:可以让你创造抽象控制从而减少代码重复。

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)) 是个闭包。

*/