理解Scala:将函数作为参数传递

时间:2013-01-24 15:01:28

标签: scala

我开始学习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)作为表达式执行,而是使表达式成为函数?

3 个答案:

答案 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。结合这篇文章,演示应阐明将函数作为参数传递的最佳实践