2009-07-05 3 views
8

Я не понимаю, почему авторы сказали, что в листинге 9.1 из «Программирование в Scala» используется закрытие. В главе 9, они показывают, как реорганизовать код в более менее дублированные формы, от этого оригинального кода:Вопрос о закрытии Scala (от «Программирование в 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

Давайте рассмотрим классическое закрытие add-n от What is a closure.

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

(define add3 (add 3)) 

(add3 4) returns 7 

В приведенном выше выражении лямбды, a является free variable, который определен в ссылке Википедии быть:

переменных упоминается в функции , что не является локальным переменным или аргумент этой функции. Upvalue - свободная переменная, которая была связана (закрыта) с закрытием.

Возвращаясь к

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

неявной функции x => x.endsWith(query) является функцией первого класса, который присваивается значение первого класса matcher и _.endsWith() закрыта над query, подобно тому, как 3 закрывает вверх a в (add 3). (add3 4) эквивалент делается matcher(file.getName).

Редактировать: Трудная часть - это функция в Scala, называемая анонимными функциями синтаксиса заполнителя. Используя _ вместо отправителя или параметра, Scala автоматически создает анонимную функцию, которую мы можем считать ее лямбда-выражением. не

Например,

_ + 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

+2

Да, в этом коде «def filesEnding (query: String) = filesMatching (_. EndsWith (query))« есть лямбда »_.endsWith (query)», который при уменьшении бит выглядит «{x => x .endsWith (запрос)}». В обозначениях схемы будет выглядеть «(lambda (x) (endwith x query))». Как вы можете видеть, в лямбда-запросе есть свободная переменная. Он не связан как аргумент или с let в лямбда, поэтому, когда замыкание сформировано, запрос захватывается из среды, содержащей среду, например. вызовы таких методов, как «filesEnding». –

Смежные вопросы