我开始学习Scala,我遇到了Scala编程教程中的一个片段,我不太明白。希望有人可以帮助我吗?
这是来自Scala编程的清单9.1,第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)
作为表达式执行,而是使表达式成为函数?
答案 0 :(得分:14)
扩展定义
匿名函数以其更详细和完整的形式定义为
(a: A, b: B, ...) => function body //using a, b, ...
E.g。
(a: String, b: String) => a ++ b // concatenates 2 Strings
推断类型
如果上下文提供了所需的信息(如高阶函数需要其函数参数的特定签名),则可以省略参数的类型,如
(a, b, ...) => function body //using a, b, ...
E.g。
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
每个_
都是函数参数的占位符
E.g。
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)
答案 1 :(得分:3)
这里使用的_
是函数参数的简写。因此filesMatching(_.endsWith(query))
相当于filesMatching(f => f.endsWith(query))
。由于filesMatching
具有String => Boolean
的函数作为参数,编译器可以在此处推断f
应该是String
。所以你是对的,这个表达式是一个匿名函数。
答案 2 :(得分:0)
这种操作最好通过定义函数类型来完成。我发现了一个很好的示范here。结合这篇文章,演示应阐明将函数作为参数传递的最佳实践