2009-07-05 5 views
8

Ich verstehe nicht, warum Autoren sagten, dass Code Listing 9.1 von "Programmierung in Scala" Schließung verwenden. In Kapitel 9, zeigen sie, wie Code in mehr weniger duplizierte Form Refactoring, aus diesem ursprünglichen Code:Frage zu Scala Closure (aus "Programmierung in 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 
} 

Zur zweiten Version:

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(_)) 
} 

Was sie sagte, dass es keine Verwendung von Verschluss Hier. Jetzt verstehe ich bis zu diesem Punkt. Allerdings führten sie die Verwendung von Schließung Refactoring noch einige weitere, 9,1 in Listing gezeigt:

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)) 
} 

Jetzt sagte sie, dass Abfrage eine freie Variable ist, aber ich weiß nicht wirklich verstehen, warum sie das so? Seit "" query "" scheint von der Top-Methode bis zur String-Matching-Funktion explizit weitergegeben zu werden.

Antwort

17

Schauen wir uns den klassischen Add-n-Verschluss von What is a closure an.

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

(define add3 (add 3)) 

(add3 4) returns 7 

In dem obigen Lambda-Ausdruck ist a die free variable, die in den Empfehlungen definiert sein:

eine Variable in Abhängigkeit bezeichnet, die nicht eine lokale Variable oder ist Argument dieser Funktion. Ein upvalue ist eine freie Variable, die mit einem Abschluss (geschlossen) gebunden wurde.

Kommen wir zurück zu

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

Die implizite Funktion x => x.endsWith(query) ist der First-Class-Funktion, die matcher erstklassige Wert zugewiesen wird, und _.endsWith() über query, ähnlich wie 3 schließt geschlossen bis a in (add 3). (add3 4) entspricht matcher(file.getName).

Bearbeiten: Tricky Teil ist die Funktion in Scala namens Platzhalter-Syntax anonyme Funktionen. Wenn Sie anstelle des Absenders oder des Parameters _ verwenden, erstellt Scala automatisch eine anonyme Funktion, die wir als Lambda-Ausdruck betrachten können.

Zum Beispiel

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

Innerhalb der Funktion x => x.endsWith(query), query die beiden Anforderungen erfüllt eine freie Variable des Seins:

  1. query ist keine lokale Variable innerhalb der Funktion definiert (es gibt keine lokale Variable).
  2. query ist kein Argument der Funktion (das einzige Argument ist x).
+1

Bin ich richtig verstehen, dass, weil "Matcher" -Methode Variable "Abfrage" erfassen daher es Schließung verwenden. – Ekkmanz

+2

Ja, in diesem Code "def filesEnding (Abfrage: String) = filesMatching (_. EndsWith (Query))" Es gibt ein Lambda "_.endsWith (Query)" was beim Entzucken ein bisschen wie aussieht "{x => x .endsWith (Abfrage)} ". In schematischer Notation würde aussehen wie "(Lambda (x) (Ende mit x Abfrage))". Wie Sie sehen können, ist im Lambda "Abfrage" eine freie Variable. Es ist weder als ein Argument noch als ein Wert in dem Lambda gebunden, so dass, wenn der Abschluss gebildet wird, eine Abfrage aus der enthaltenden Umgebung, z. Aufrufe von Methoden wie "filesEnding". –