在Scala中,':_*'(冒号下划线星号)有什么作用?

z8dt9xmd  于 2022-11-23  发布在  Scala
关注(0)|答案(4)|浏览(109)

下面的代码是从this question得到的:

def addChild(n: Node, newChild: Node) = n match {
  case Elem(prefix, label, attribs, scope, child @ _*) => Elem(prefix, label, attribs, scope, child ++ newChild : _*)
  case _ => error("Can only add children to elements!")
}

里面的一切都很清楚,除了这一段:child ++ newChild : _*
它是做什么的?
我知道有Seq[Node]与另一个Node连接在一起,然后呢?: _*是做什么的?

j8ag8udp

j8ag8udp1#

它会“splats“1序列。
查看构造函数签名

new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding,
         child: Node*)

称为

new Elem(prefix, label, attributes, scope,
         child1, child2, ... childN)

但这里只有一个序列,没有child1child2等,因此这允许将结果序列用作构造器的输入。
1在SLS中没有一个可爱的名字,但这里有一些细节。重要的是,它改变了Scala将参数绑定到具有重复参数的方法的方式(如上面的Node*所示)。

_*类型注解包含在SLS的“4.6.2重复参数”中。

参数段的最后一个值参数可以用“*"作为后缀,例如(...,x:T )。方法中这样一个重复参数的类型是序列类型scala.Seq[T]。具有重复参数T * 的方法采用可变数量的类型T的参数。也就是说,如果方法m具有类型(p1:T1,...,PN:Tn,ps:S)U应用于自变量(e1,. . .,ek),其中k〉= n,则在该应用中m被取为具有类型(p1:T1,...,PN:Tn,ps:S,. . .,ps 0 S)U,出现k ~ n次S类型,其中ps以外的任何参数名都是新的。此规则的唯一例外是最后一个参数通过_ 类型注解标记为序列参数。如果将上面的m应用于参数(e1,. . .,en,e0:_),则在该应用中M的类型被取为(P1:T1,...,PN:Tn,ps:阶数序列[S])**

1l5u6lss

1l5u6lss2#

  • child ++ newChild-序列
  • :-类型归属,帮助编译器理解表达式类型的提示
  • _*-接受任何值+ vararg运算符的占位符

child ++ newChild : _*Seq[Node]扩展为Node*(告诉编译器我们更愿意使用varargs,而不是序列)。对于只能接受varargs的方法特别有用。

mpbci0fu

mpbci0fu3#

以上所有答案看起来都很棒,但只需要一个例子来解释这一点。这里是:

val x : Seq[Seq[Int]] = Seq(Seq(1),Seq(2))

def f(arg: Seq[Any]*) : Int = {
 arg.length
}
f(x) //1 as x is taken as single arg
f(x:_*)  // 2 as x is "unpacked" as a Seq[Any]*

现在我们知道:_*的作用是告诉编译器:请解压缩此参数并将这些元素绑定到函数调用中的vararg参数,而不是将x作为单个参数。
所以简单地说,:_*是为了在传递变元给vararg参数时消除歧义。

e5nqia27

e5nqia274#

对于像我这样的懒人来说,它只是将集合值转换为varArgs!

相关问题