2013-01-24 31 views
6

我开始学习Scala,并且我遇到了Scala教程中的一个片段,我不太明白。希望有人能帮助我吗?了解Scala:将函数作为参数传递

这是来自程序清单9.1的Programming in Scala,2nd Edition。

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)作为表达式,而是使该表达式成为函数?

+1

上面没有任何包含'// ???'的行。也许你忘了添加这些? –

+0

对不起,现在添加了'// ???'。 – C0deAttack

+0

[Scala \ _占位符(此代码如何工作?)]的可能重复(http://stackoverflow.com/questions/6880407/scala-placeholders-how-does-this-code-function) –

回答

14

扩展定义

匿名功能被定义,在它们的更详细的和完整的形式,如

(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, ... 

Eg

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 

每个_是函数的参数

的占位符3210

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) 
3

这里使用的_是函数参数的简写。因此filesMatching(_.endsWith(query))相当于filesMatching(f => f.endsWith(query))。由于filesMatching具有String => Boolean的函数作为参数,因此编译器可以推断f在此处预期为String。所以你是对的,这个表达式是一个匿名函数。

0

这种操作是最好的定义函数类型来完成。我发现了一个很好的演示here。结合这篇文章,演示应该澄清将函数作为参数传递的最佳实践