2009-07-05 12 views
8

「Scalaのプログラミング」のコードリスト9.1がクロージャを使用している理由を著者が言った理由はわかりません。Scala Closureに関する質問(「Scalaのプログラミング」から)

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

彼らは閉鎖のない使用がないことを言った:第二版に

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 
} 

:第9章では、彼らはこの元のコードから、より少ない重複フォームにコードをリファクタリングする方法を示していますここに。今私はこの点まで理解しています。しかし彼らは、リスト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

従来のadd-nクロージャーをWhat is a closureから見てみましょう。上記のラムダ式で

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

(define add3 (add 3)) 

(add3 4) returns 7 

aであることがWikipediaのリンクで定義されているfree variable、ある:

ローカル変数またはANない関数 にいう変数その機能の引数は です。上位値 は、閉鎖で (閉じている)にバインドされているフリー変数です。陰関数x => x.endsWith(query) 3閉じる方法と同様に、ファーストクラスの値matcherに割り当てられている第一級関数であり、そして_.endsWith()queryにわたって閉鎖されるバック

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

に来る

a(add 3)に設定してください。 (add3 4)相当はmatcher(file.getName)によって行われます。

:トリッキーパートは、プレースホルダーシンタックスの無名関数と呼ばれるScalaの機能です。送信者またはパラメータの代わりに_を使用すると、Scalaは無名関数を自動的に作成します。この関数はラムダ式と見なすことができます。例えば

、機能x => x.endsWith(query)

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

queryは自由変数であるという二つの要求を満たす:

  1. queryは関数内で定義されたローカル変数はない(存在しませんローカル変数)。
  2. queryは(唯一の引数がxある)関数の引数ではありません。
+1

"matcher"メソッドは変数 "query"をキャプチャするため、クロージャを使用するため、正しく理解していますか? – Ekkmanz

+2

はい、このコードでは、 "def filesEnding(query:String)= filesMatching(_。endsWith(query))"という名前のラムダ "_.endsWith(query)"があります。 .endsWith(クエリ)} " schemey表記では、 "(lambda(x)(endwith x query))"のようになります。あなたが見ることができるように、ラムダ "クエリ"は自由変数です。それは引数としてもラムダのletでもバインドされていないので、クロージャが形成されるときに、クエリーが格納環境からキャプチャされます。 "filesEnding"のようなメソッドの呼び出し。 –

関連する問題