带有Scala的List.map中的下划线和字符串连接

时间:2014-10-08 21:04:02

标签: scala lambda scala-collections scala-placeholder-syntax

Scala允许您使用下划线来执行简单的地图。例如,而不是写:

def roleCall(people: String*){
  people.toList.map(x => println(x))
}  

......我可以写一下:

def roleCall(people: String*){
  people.toList.map(println(_))
}  

但出于某种原因我不能写:

def greet(people: String*){
  // This won't compile!
  people.toList.map(println("Hello " + _))
}

相反,我必须写:

def greet(people: String*){
  people.toList.map(x => println("Hello " + x))
}

任何人都可以解释原因吗?

1 个答案:

答案 0 :(得分:1)

基本上,只有在没有嵌套括号的情况下,函数定义的简写语法才能正常工作。这是因为每个嵌套级别都会创建自己的下划线所在的范围。在REPL中,您可以检查例如:

scala> val list = List(1,2,3).map(_ + 1)
list: List[Int] = List(2, 3, 4)

scala> val list = List(1,2,3).map((_ + 1))
list: List[Int] = List(2, 3, 4)

两者都有效,但是一旦在括号后添加任何内容,就会出现错误:

val list = List(1,2,3).map((_ + 1) + 1)
<console>:58: error: missing parameter type for expanded function ((x$1) => x$1.$plus(1))
       val list = List(1,2,3).map((_ + 1) + 1)

如您所见,错误仅与函数(_ + 1)(在消息中显示为((x$1) => x$1.$plus(1)))有关,而不是与整个表达式(_ + 1) + 1有关,因此括号中的部分被视为一个单独的函数,下划线_在这个内部函数的范围内解释,而不是外部函数。

我不确定为什么List(1,2,3).map(println(_))有效,但似乎是一些边缘情况,由于单一论证似乎仅仅是巧合。我很高兴自己能够了解细节。无论如何,在带有下划线的匿名函数定义中使用括号肯定会迟早引起麻烦,最好避免它。