为了补充其他答案,这里有一些示例说明为什么在某些情况下使用“_”作为占位符参数时会出现“缺少参数类型”。
Scala 的类型推断根据其上下文考虑表达式的“预期”类型。如果没有上下文,则无法推断参数的类型。请注意,在错误消息中,_ 的第一个和第二个实例被替换为编译器生成的标识符 x$1 和 x$2。
scala> _ + _
<console>:5: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
_ + _
^
<console>:5: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
_ + _
^
为整个表达式添加类型归属提供了足够的上下文来帮助推理器:
scala> (_ + _) : ((Int, Int) => Int)
res3: (Int, Int) => Int = <function2>
或者,您可以为每个参数占位符添加类型说明:
scala> (_: Int) + (_: Int)
res4: (Int, Int) => Int = <function2>
在下面提供类型参数的函数调用中,上下文是明确的并且函数类型是推断出来的。
scala> def bar[A, R](a1: A, a2: A, f: (A, A) => R) = f(a1, a2)
bar: [A,R](a1: A,a2: A,f: (A, A) => R)R
scala> bar[Int, Int](1, 1, _ + _)
res5: Int = 2
但是,如果我们要求编译器推断类型参数,如果失败:
scala> bar(1, 1, _ + _)
<console>:7: error: missing parameter type for expanded function ((x$1, x$2) => x$1.$plus(x$2))
bar(1, 1, _ + _)
^
<console>:7: error: missing parameter type for expanded function ((x$1: <error>, x$2) => x$1.$plus(x$2))
bar(1, 1, _ + _)
^
不过,我们可以通过对参数列表进行柯里化来帮助它。这里,第一个参数列表(1, 1) 的参数告诉推断类型参数A 应该是Int。然后它知道参数f的类型必须是(Int, Int) => ?),返回类型R推断为Int,整数加法的结果。您将在标准库中看到 Traversable.flatMap 中使用的相同方法。
scala> def foo[A, R](a1: A, a2: A)(f: (A, A) => R) = f(a1, a2)
foo: [A,R](a1: A,a2: A)(f: (A, A) => R)R
scala> foo[Int, Int](1, 1) { _ + _ }
res1: Int = 2
scala> foo(1, 1) { _ + _ }
res0: Int = 2