6

我开始学习 Scala,并且遇到了我不太了解的 Programming in Scala 教科书中的一个片段。希望有人能帮助我吗?

这是来自 Programming in Scala, 2nd Edition 的清单 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)) // ???

我对有// ???. 是否使用_某种方式创建了一个传递给的匿名函数filesMatching?还是_与此无关,而是编译器认为filesMatching需要一个函数,因此不_.endsWith(query)作为表达式执行,而是使表达式成为函数?

4

3 回答 3

14

扩展定义

匿名函数以更详细和完整的形式定义为

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

例如

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

推断类型

如果上下文提供了所需的信息(例如,当高阶函数期望其函数参数具有特定签名时),您可以省略参数的类型,如

(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)
于 2013-01-24T15:29:22.903 回答
3

此处使用的_是函数参数的简写。因此filesMatching(_.endsWith(query))等价于filesMatching(f => f.endsWith(query))。与filesMatching的函数作为参数一样String => Boolean,编译器可以推断出这里f应该是 a String。所以你是对的,这个表达式是一个匿名函数。

于 2013-01-24T15:10:37.053 回答
0

这种操作最好通过定义函数类型来完成。我在这里找到了一个很好的演示。结合这篇文章,演示应该阐明将函数作为参数传递的最佳实践

于 2017-09-14T18:01:41.360 回答