当Row确实接受varargs时,为什么Scala编译器会因"no':_*'这里允许的注释"而失败?

BMe*_*iot 7 scala apache-spark apache-spark-sql

我想在Row不知道其编号的情况下创建一个包含多个参数的参数.我在Scala中写了这样的东西:

def customRow(balance: Int,
              globalGrade: Int,
              indicators: Double*): Row = {
    Row(
      balance,
      globalGrade,
      indicators:_*
    )
}
Run Code Online (Sandbox Code Playgroud)

Spark GitHub上,该Row对象似乎接受了:_*考虑其apply方法的符号:

def apply(values: Any*): Row = new GenericRow(values.toArray)
Run Code Online (Sandbox Code Playgroud)

但是在编译时,似乎不允许这样做:

Error:(212, 19) no ': _*' annotation allowed here
(such annotations are only allowed in arguments to *-parameters)
        indicators:_*
Run Code Online (Sandbox Code Playgroud)

我错过了什么?

Rob*_*let 10

这个最小的例子可以更好地解释为什么不允许你想做的事情:

def f(a: Int, b: Int, c: Int, rest: Int*) = a + b + c + rest.sum

val ns = List(99, 88, 77)

f(11, 22, 33, 44, ns:_*) // Illegal
f(11, 22, 33,     ns:_*) // Legal
f(11, 22,         ns:_*) // Illegal
Run Code Online (Sandbox Code Playgroud)

基本上,您可以:_*仅使用语法将序列作为vararg参数直接传递rest,但它是全有或全无.序列的项不在simple参数和vararg参数之间共享,并且vararg参数不能从简单参数和提供的序列中收集值.

在你的情况下,你试图调用Row好像它有两个简单的参数,然后是一个vararg,但事实并非如此.当您自己创建序列时,您将使其正确适合签名.

请注意,在动态类型编程语言中,这通常不是问题.例如,在Python中:

>>> def f(a, b, c, *rest):
    return a + b + c + sum(rest)

>>> ns = [99, 88, 77]
>>> f(11, 22, 33, 44, *ns)
374
>>> f(11, 22, 33, *ns)
330
>>> f(11, 22, *ns)
297
Run Code Online (Sandbox Code Playgroud)


BMe*_*iot 6

通过添加一个中间 Seq 来解决它:

def customRow(balance: Int,
              globalGrade: Int,
              indicators: Double*): Row = {

  val args = Seq(
    balance,
    globalGrade
  ) ++ indicators

    Row(
      args:_*
    )
}
Run Code Online (Sandbox Code Playgroud)

但是,我仍然不知道它为什么有效。