为什么scala lambda与_不能使用&&结合两个bool表达式

时间:2015-11-23 03:20:30

标签: scala lambda

据我了解。 _是一个简短的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 =>之间存在更多差异?

3 个答案:

答案 0 :(得分:6)

在scala中,任何_占位符都与调用函数上下文中传递的参数匹配。因此,例如,如果您尝试使用的函数的签名是f : A ⇒ B,并且您正在调用类似collectionOfFunctA.map(_.f)的函数 - Scala编译器将推断函数的正确类型,并将使用第一个下划线放置集合中的实际项目,并在其上调用函数f。但是如果您尝试将其写为collectionOfFunctA.map(_.f + _.size) - 那将失败,因为Scala编译器会选择第一个占位符,其类型具有定义的函数f,并且第二个下划线将不匹配任何函数在上下文中。所以它希望一个带两个参数而不是一个的函数。

More on this

答案 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