2009-07-05 3 views
8

필자가 "스칼라로 프로그래밍"의 코드 9.1이 클로저를 사용한다고 말한 이유를 알지 못합니다.스칼라 클로저에 대한 질문 ("스칼라 프로그래밍"에서)

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 장, 그들은이 원래의 코드에서, 더 적은 중복 된 형태로 코드를 리팩토링하는 방법을 보여줍니다 이리. 이제 나는이 시점까지 이해한다.

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

지금 그들이 쿼리 자유 변수라고 말했지만 그들이 그렇게 말했다 왜 난 정말 이해가 안 : 그러나 그들은 좀 더, 9.1 목록에 표시도 리팩토링하는 폐쇄의 사용을 도입? ""쿼리 ""가기 메서드에서 문자열 일치 함수를 명시 적으로 전달 된 것으로 보인다.

답변

17

고전적인 add-n 클로저를 What is a closure에서 살펴 보겠습니다. 상기 람다 식에서

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

(define add3 (add 3)) 

(add3 4) returns 7 

a이 될 위키 피디 링크에 정의 free variable이다 :

는 A 지역 가변인지 기능 에 언급 된 변수 해당 함수의 인수는 입니다. 상위 값 은 클로저로 (닫힌 상태)으로 바인드 된 무료 변수입니다.

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

내재적 기능 x => x.endsWith(query)로 돌아와

일류 값 matcher에 할당 일류 함수이며 _.endsWith()query 통해 유사한 방식으로 닫힌 3 개 폐쇄 a(add 3)입니다. (add3 4)matcher(file.getName)에 해당합니다.

편집 : 까다로운 부분은 자리 표시 자 구문 익명 함수라고하는 스칼라의 기능입니다. 보낸 사람이나 매개 변수 대신 _을 사용하면 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"를 캡처하므로 closure를 사용하기 때문에 올바르게 이해합니다. – Ekkmanz

+2

예,이 코드에서 "def filesEnding (query : String) = filesMatching (_. endsWith (query))"람다 "_.endsWith (query)"가 있는데,이 때 "{x => x .endsWith (쿼리)} ". schemey 표기법에서는 "(lambda (x) (endwith x query))"와 같이 보입니다. 보시다시피, 람다에서 "쿼리"는 자유 변수입니다. 그것은 인수로서 또는 람다에있는 let으로 묶여 있지 않으므로 클로저가 형성 될 때 질의는 포함하는 환경에서 캡처됩니다. "filesEnding"과 같은 메소드의 호출. –