W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
在前面的文章中,我們說過 Scala 沒有內(nèi)置很多控制結(jié)構(gòu),這是因?yàn)?Scala 賦予了程序員自己擴(kuò)展控制結(jié)構(gòu)的能力。Scala 支持函數(shù)值(值的類型為函數(shù),而非函數(shù)的返回值),為避免混淆,我們使用函數(shù)類型值來指代類型為函數(shù)的值。
所有的函數(shù)可以分成兩個(gè)部分:一是共有部分,這部分在該函數(shù)的調(diào)用都是相同的,另外一部分為分公共部分,這部分在每次調(diào)用該函數(shù)上是可以不同的。公共部分為函數(shù)的定義體,非公共部分為函數(shù)的參數(shù)。但你使用函數(shù)類型值做為另外一個(gè)函數(shù)的參數(shù)時(shí),函數(shù)的非公共部分本身也是一個(gè)算法(函數(shù)),調(diào)用該函數(shù)時(shí),每次你都可以傳入不同函數(shù)類型值作為參數(shù),這個(gè)函數(shù)稱為高階函數(shù)–函數(shù)的參數(shù)也可以是另外一個(gè)函數(shù)。
使用高級(jí)函數(shù)可以幫助你簡化代碼,它支持創(chuàng)建一個(gè)新的程序控制結(jié)構(gòu)來減低代碼重復(fù)。比如,你打算寫一個(gè)文件瀏覽器,你需要寫一個(gè) API 支持搜索給定條件的文件。首先,你添加一個(gè)方法,該方法可以通過查詢包含給定字符串的文件,比如你可以查所有“.scala”結(jié)尾的文件。你可以定義如下的 API:
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
def filesEnding(query : String) =
for (file <-filesHere; if file.getName.endsWith(query))
yield file
}
filesEnding 方法從本地目錄獲取所有文件(方法 filesHere),然后使用過濾條件(文件以給定字符串結(jié)尾)輸出給定條件的文件。
到目前為止,這代碼實(shí)現(xiàn)非常好也沒有什么重復(fù)的代碼。后來,你有需要使用新的過濾條件,文件名包含指定字符串,而不僅僅以某個(gè)字符串結(jié)尾的文件列表。你有實(shí)現(xiàn)了下面的 API。
def filesContaining( query:String ) =
for (file <-filesHere; if file.getName.contains(query))
yield file
filesContaining 和 filesEnding 的實(shí)現(xiàn)非常類似,不同點(diǎn)在于一個(gè)使用 endsWith,另一個(gè)使用 contains 函數(shù)調(diào)用。有過了一段時(shí)間,你有想支持使用正則表達(dá)式來查詢文件,你有實(shí)現(xiàn)了下面的對(duì)象方法:
def filesRegex( query:String) =
for (file <-filesHere; if file.getName.matches(query))
yield file
這三個(gè)函數(shù)的算法非常類似,所不同的是過濾條件稍有不同,在 Scala 中我們可以定義一個(gè)高階函數(shù),將這三個(gè)不同過濾條件抽象稱一個(gè)函數(shù)作為參數(shù)傳給搜索算法,我們可以定義這個(gè)高階函數(shù)如下:
def filesMatching( query:String,
matcher: (String,String) => Boolean) = {
for(file <- filesHere; if matcher(file.getName,query))
yield file
}
這個(gè)函數(shù)的第二個(gè)參數(shù) matcher 的類型也為函數(shù)(如果你熟悉 C#,類似于 delegate),該函數(shù)的類型為 (String,String ) =>Boolean,可以匹配任意使用兩個(gè) String 類型參數(shù),返回值類型為 Boolean 的函數(shù)。使用這個(gè)輔助函數(shù),我們可以重新定義 filesEnding,filesContaining 和 filesRegex。
def filesEnding(query:String) =
filesMatching(query,_.endsWith(_))
def filesContaining(query:String)=
filesMatching(query,_.contains(_))
def filesRegex(query:String) =
filesMatching(query,_.matches(_))
這個(gè)新的實(shí)現(xiàn)和之前的實(shí)現(xiàn)已經(jīng)簡化了不少,實(shí)際上代碼還可以簡化,我們注意到參數(shù) query 在 filesMatching 的作用只是把它傳遞給 matcher 參數(shù),這種參數(shù)傳遞實(shí)際也是無需的,簡化后代碼如下:
object FileMatcher {
private def filesHere = (new java.io.File(".")).listFiles
def filesMatching(
matcher: (String) => Boolean) = {
for(file <- filesHere; if matcher(file.getName))
yield file
}
def filesEnding(query:String) =
filesMatching(_.endsWith(query))
def filesContaining(query:String)=
filesMatching(_.contains(query))
def filesRegex(query:String) =
filesMatching(_.matches(query))
}
函數(shù)類型參數(shù) .endsWith(query),.contains(query)和_.matches(query)為函數(shù)閉包,因?yàn)樗鼈兘壎艘粋€(gè)自由變量 query,因此我們可以看到閉包也可以用來簡化代碼。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: