2009-07-05 26 views
8

我不明白爲什麼作者說「Scala編程」中的代碼9.1使用閉包。在第9章,他們展示如何重構代碼轉換成更少重複的形式,從這種原始代碼:關於Scala Closure的問題(來自「Scala編程」)

object FileMatcher { 
    private def filesHere = (new java.io.File(".")).listFiles 
    def filesEnding(query: String) = 
    for (file <- filesHere; if file.getName.endsWith(query)) 
     yield file 
    def filesContaining(query: String) = 
    for (file <- filesHere; if file.getName.contains(query)) 
     yield file 
    def filesRegex(query: String) = 
    for (file <- filesHere; if file.getName.matches(query)) 
     yield file 
} 

到了第二個版本:

object FileMatcher { 
    private def filesHere = (new java.io.File(".")).listFiles 
    def filesMatching(query: String, 
    matcher: (String, String) => Boolean) = { 
     for (file <- filesHere; if matcher(file.getName, query)) 
     yield file 
    }  
    def filesEnding(query: String) = 
    filesMatching(query, _.endsWith(_)) 
    def filesContaining(query: String) = 
    filesMatching(query, _.contains(_)) 
    def filesRegex(query: String) = 
    filesMatching(query, _.matches(_)) 
} 

,他們說,是沒有用封閉的這裏。現在我明白直到這一點。不過,他們推出了採用關閉的,甚至重構多一些,如清單9.1所示:

object FileMatcher { 
    private def filesHere = (new java.io.File(".")).listFiles 
    private 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)) 
} 

現在,他們說,查詢是自由變量,但我真的不明白他們爲什麼這麼說?由於「」查詢「」似乎是從頂部方法明確傳遞到字符串匹配函數。

回答

17

讓我們看看來自What is a closure的經典add-n關閉。

(define (add a) 
    (lambda (b) 
    (+ a b))) 

(define add3 (add 3)) 

(add3 4) returns 7 

在上述λ表達式,afree variable,其在維基百科鏈路定義爲:

在函數 稱爲一個變量,它是不是本地變量或該函數的參數爲​​ 。正價 是一個自由變量,已綁定 (封閉)與閉包。

再回到

def filesEnding(query: String) = 
    filesMatching(_.endsWith(query)) 

隱函數x => x.endsWith(query)是頭等函數,其被分配給第一級的值matcher,並且_.endsWith()閉合超過query,類似方式3關閉up a in (add 3)(add3 4)等效由matcher(file.getName)完成。

編輯:Tricky部分是Scala中稱爲佔位符語法匿名函數的功能。通過使用_代替發件人或參數,Scala會自動創建一個匿名函數,我們可以將其視爲lambda表達式。

例如,

_ + 1    creates  x => x + 1 
_ * _    creates  (x1, x2) => x1 * x2 
_.endsWith(query) creates  x => x.endsWith(query) 

在函數x => x.endsWith(query)query滿足在一個自由變量的兩個要求:

  1. query不是函數中定義的局部變量(沒有局部變量)。
  2. query不是函數的參數(唯一的參數是x)。
+1

我正確理解,因爲「匹配器」方法捕獲變量「查詢」,因此它使用閉包。 – Ekkmanz 2009-07-05 05:26:23