可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I have such a piece of code from 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!") }
Everything in it is pretty clear, except this piece: child ++ newChild : _*
What does it do? I under stand there is Seq[Node] concatenated with another Node, and then? What does : _*
do?
回答1:
It "splats"1 the sequence.
Look at the constructor signature
new Elem(prefix: String, label: String, attributes: MetaData, scope: NamespaceBinding, child: Node*)
which is called as
new Elem(prefix, label, attributes, scope, child1, child2, ... childN)
but here there is only a sequence, not child1
, child2
, etc. so this allows the result sequence to be used as the input to the constructor.
Happy coding.
1 This doesn't have a cutesy-name in the SLS, but here are the details. The important thing to get is that it changes how Scala binds the arguments to the method with repeated parameters (as denoted with Node*
above).
The _*
type annotation is covered in "4.6.2 Repeated Parameters" of the SLS.
The only exception to this rule is if the last argument is marked to be a sequence argument via a _* type annotation. If m above is applied to arguments (e1, . . . , en,e0 : _*), then the type of m in that application is taken to be (p1 : T1, . . . , pn : Tn,ps :scala.Seq[S])
回答2:
child ++ newChild
- sequence :
- type ascription, a hint that helps compiler to understand, what type does that expression have _*
- placeholder accepting any value + vararg operator
child ++ newChild : _*
expands Seq[Node]
to Node*
(tells the compiler that we're rather working with a varargs, than a sequence). Particularly useful for the methods that can accept only varargs.
回答3:
All the above answer looks great, but just need a sample to explain this . Here it is :
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]*
So now we know what :_*
do is to tell compiler : please unpack this argument and bind those elements to the vararg parameter in function call rather than take the x as a single argument .
So in a nutshell, the :_*
is to remove ambiguity when pass argument to vararg parameter.