当 Row 接受可变参数时,为啥 Scala 编译器会失败并显示“此处不允许 ': _*' 注释”?

Posted

技术标签:

【中文标题】当 Row 接受可变参数时,为啥 Scala 编译器会失败并显示“此处不允许 \': _*\' 注释”?【英文标题】:Why does Scala compiler fail with "no ': _*' annotation allowed here" when Row does accept varargs?当 Row 接受可变参数时,为什么 Scala 编译器会失败并显示“此处不允许 ': _*' 注释”? 【发布时间】:2018-09-03 15:34:03 【问题描述】:

我想创建一个带有多个参数的Row,但不知道它们的编号。我在 Scala 中写了这样的东西:

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

在Spark GitHub 上,考虑到apply 方法,Row 对象似乎接受:_* 表示法:

def apply(values: Any*): Row = new GenericRow(values.toArray)

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

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

我错过了什么?

【问题讨论】:

【参考方案1】:

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

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

基本上,您只能使用:_* 语法将序列作为可变参数rest 直接传递,但这是全有或全无。序列的项目不会在简单参数和可变参数之间共享,可变参数不能同时从简单参数和提供的序列中收集值。

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

请注意,在动态类型的编程语言中,这通常不是问题。例如,在 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

【讨论】:

【参考方案2】:

通过添加中间 Seq 解决它:

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

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

    Row(
      args:_*
    )

但是,我仍然不知道它为什么会起作用。

【讨论】:

以上是关于当 Row 接受可变参数时,为啥 Scala 编译器会失败并显示“此处不允许 ': _*' 注释”?的主要内容,如果未能解决你的问题,请参考以下文章

如何在Scala中添加另一个参数时传递可变参数?

为啥我的可变参数宏不能正确接受任何参数?

当初始化列表可用时,为啥现在使用可变参数?

为啥视图修饰符不能接受不可变变量?

为啥编译器不能通过逗号运算符扩展可变参数模板的参数?

将数组传递给 TypeScript 中的可变参数函数