据我了解。 _是一个简短的lambda,省略a =>
我找到了这段代码(可以在scala-function-true-power找到)
val file = List("warn 2013 msg", "warn 2012 msg", "error 2013 msg", "warn 2013 msg")
val size = file.filter(_.contains("warn")).filter(_.contains("2013")).size
//val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
val size2 = file.filter( a=> a.contains("warn") && a.contains("2013")).size
println("cat file | grep 'warn' | grep '2013' | wc : " +size )
获取size1的行有语法错误,看起来它无法识别" _" ,它不是fileList中的元素。
但我使用的是=>,正常的,它运作良好。
那么,为什么scala会以这种方式工作?
_和a =>之间存在更多差异?
答案 0 :(得分:6)
在scala中,任何_占位符都与调用函数上下文中传递的参数匹配。因此,例如,如果您尝试使用的函数的签名是f : A ⇒ B
,并且您正在调用类似collectionOfFunctA.map(_.f)
的函数 - Scala编译器将推断函数的正确类型,并将使用第一个下划线放置集合中的实际项目,并在其上调用函数f
。但是如果您尝试将其写为collectionOfFunctA.map(_.f + _.size)
- 那将失败,因为Scala编译器会选择第一个占位符,其类型具有定义的函数f
,并且第二个下划线将不匹配任何函数在上下文中。所以它希望一个带两个参数而不是一个的函数。
答案 1 :(得分:3)
正如jdevelop所说,但在这里用编译器/ REPL的话来说:
scala> val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
<console>:8: error: missing parameter type for expanded function ((x$1, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
<console>:8: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.contains("warn").$amp$amp(x$2.contains("2013")))
val size1 = file.filter(_.contains("warn") && _.contains("2013")).size
^
你看到提示:扩展功能((x $ 1,x $ 2)=&gt; x $ 1.contains(“警告”)。$ amp $ amp(x $ 2.contains(“2013”)))
只有一个参数需要2个参数。
答案 2 :(得分:2)
您可以将占位符视为与lambda的参数位置匹配。
_
的第一次出现与第一个参数匹配,第二次出现与第二个参数匹配,等等。
正如其他答案所示,这意味着使用占位符两次将被试图将带有2个参数的lamba传递给过滤器,该过滤器只需要一个。
在你的例子中:
val size = file.filter(_.contains("warn") && _.contains("2013")).size
将被视为
val size = file.filter((a,b)=>a.contains("warn") && b.contains("2013")).size
由于过滤器需要谓词p: A => Boolean
,因此将无法编译
现在,占位符匹配位置的一个原因是为了避免使用多个参数的lambda中存在歧义。
如果占位符可以多次重复使用相同的参数,编译器如何猜测以下情况的正确实现:
file.fold("")(_++_)
它应该被贬低为:
file.fold("")((a,b)=> a++b )
或
file.fold("")((a,b)=> a++a )
或
file.fold("")((a,b)=> b++b )
更糟糕的是,您对
的期望是什么?file.fold("")(_++_++_)
编译器没有通用的方法来推断正确的实现。
当预期的lambda只接受一个参数时,有人可能会主张放宽约束。我建议在迈出scala improvement process的第一步之前做一个更详细的研究,因为这个特定的设计决定似乎已经受到挑战和解释。
如果您担心两次迭代列表的性能(在您编写时就是这种情况)
file.filter(_.contains("warn")).filter(_.contains("2013")).size
理论上,编译器应该可以检测到两个过滤器都可以在同一次迭代中应用。 在scala中,默认情况下集合很急,但您可以使用视图获得 lazy 评估。 目前的实施已知问题为being worked on。正在积极开发scala中的其他集合实现,以便能够默认组合转换和计算(例如,参见psp-std)