Понимание Scala: передача функций в качестве аргументов

Я начинаю изучать Scala, и я наткнулся на фрагмент из программирования в учебнике Scala, который я не совсем понимаю. Надеялся, что кто-нибудь сможет мне помочь?

это из листинга 9.1 из программирования в Scala, 2-е издание.

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)) // ???

Я немного запутался со строки // ???. Не использовать _ Как создать анонимную функцию, которая передается filesMatching? Или _ не имеют ничего общего с этим, и вместо этого компилятор видит, что filesMatching требует функции и поэтому не выполняет _.endsWith(query) как выражение, но вместо этого делает выражение функцией?

3 ответов


расширенное определение

анонимные функции определяются, в их более подробной и полной форме, как

(a: A, b: B, ...) => function body //using a, b, ...

Э. Г.

(a: String, b: String) => a ++ b // concatenates 2 Strings

вывод типов

если контекст предоставляет необходимую информацию (например, когда функция более высокого порядка ожидает определенную подпись для своих аргументов функции), вы можете опустить типы параметров, as

(a, b, ...) => function body //using a, b, ...

Э. Г.

val l = List(1, 2, 3)

//you can omit the type because filter on List[Int] expects a (Int => Boolean)
l.filter(i => i < 3)

синтаксис заполнителя

наконец, вы можете использовать более короткую форму, если ваши параметры используются один раз и в том же порядке, в котором вы их объявляете, телом функции, как

_ ++ _ // which is equivalent to (a, b) => a ++ b

каждого _ является заполнителем для аргументов функции

Е. Г.

filesMatchingаргумент является функцией типа String => Boolean так что вы можете использовать

_.endsWith(query) // equivalent to (s: String) => s.endsWith(query)
_.contains(query) // equivalent to (s: String) => s.contains(query)
_.matches(query)  // equivalent to (s: String) => s.matches(query)

на _ как здесь используется обозначение аргумента функции. Таким образом filesMatching(_.endsWith(query)) эквивалентно filesMatching(f => f.endsWith(query)). As filesMatching имеет в качестве аргумента функцию String => Boolean, компилятор может сделать вывод, что f ожидается String здесь. Итак, вы правы, что это выражение является анонимной функцией.


этот вид операции лучше всего выполнять, определяя типы функций. Я нашел отличную демонстрацию здесь. В сочетании с этим сообщением демонстрация должна прояснить лучшие практики передачи функций в качестве аргументов