List.filter中的下划线

Rog*_*ach 9 scala

为什么这不起作用:

List(true,false).filter(_).size
Run Code Online (Sandbox Code Playgroud)

错误说:

<console>:8: error: missing parameter type for expanded function 
((x$1) => List(true, false).filter(x$1).size)
    List(true,false).filter(_).size
                            ^
Run Code Online (Sandbox Code Playgroud)

但以下作品(对我来说看起来一样):

List(true,false).filter(a => a).size
Run Code Online (Sandbox Code Playgroud)

我正在使用Scala 2.9.0.1.

Tom*_*icz 23

_在Scala中处理有点棘手,作为旁注,我认为错误处理应该有所改进.回到主题,看看这个例子:

def twice(i: Int) = i * 2
def gt2(j: Int) = j > 2

List(1,2,3) filter gt2
Run Code Online (Sandbox Code Playgroud)

这编译好并按预期工作.但是,尝试撰写函数会导致隐藏错误:

List(1,2,3) filter gt2(twice(_))

  error: missing parameter type for expanded function ((x$1) => twice(x$1))
          List(1,2,3) filter gt2(twice(_))
                                     ^ 
Run Code Online (Sandbox Code Playgroud)

发生了什么?基本上,当Scala编译器看到下划线时,它会将其绑定到最直接的上下文中,twice(_)在这种情况下.这意味着我们现在gt2()使用函数 twice作为参数进行调用.编译器知道的是该函数接受一个参数并返回相同的类型.可以说它应该弄清楚这个参数的类型,并且返回类型是Int基于twice()签名的,但是它x$1暂时使用占位符,直到他稍后想出来.

不幸的是,它无法做到这一点,因为我们gt2()期待一段Int时间我们提供一个函数(至少这是编译器认为的).

那么为什么:

List(1,2,3) filter {k => gt2(twice(k))}
Run Code Online (Sandbox Code Playgroud)

工作?编译器k事先不知道类型.然而,它知道gt2回报Boolean和预期的Int.它也知道twice()期望a Int并返回一个.这样它就可以推断出它的类型k.另一方面,编译器从一开始就知道filter期望Int => Boolean.


这是回到你的情况.单独的下划线((_))不考虑" 上下文 ",因此编译器会搜索另一个最直接的封闭上下文.在!_过去被认为与自身的功能,以及_ == true.但不仅仅是下划线.

那么在这种情况下,最接近的直接背景是什么(我确定有一个科学名称......)?好吧,整个表达方式:

(x$1) => List(true, false).filter(x$1).size
Run Code Online (Sandbox Code Playgroud)

编译器认为您正在尝试创建一个函数,该函数接受一些未知类型的参数并返回表达式的某些类型:List(true, false).filter(x$1).size.再次可以说它应该能够找出filtertake Boolean => Boolean和returns Int(.size),但显然它没有.


所以,你可以做什么?您必须为编译器提供一个提示,即应在较小的上下文中解释下划线.你可以说:

List(true,false) filter (_ == true)
List(true,false) filter (i => i)
List(true,false) filter identity
Run Code Online (Sandbox Code Playgroud)