O que `: _ *` (estrela de sublinhado do cólon) faz no Scala?

Eu tenho o seguinte trecho de código desta pergunta :

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!") } 

Tudo está bem claro, exceto esta parte: child ++ newChild : _*

O que isso faz?

Eu entendo que há Seq[Node] concatenado com outro Node , e então? O que faz : _* fazer?

Ele “splats” 1 a seqüência.

Olhe para a assinatura do construtor

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

que é chamado como

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

mas aqui há apenas uma sequência, não child1 , child2 , etc., portanto, isso permite que a sequência de resultados seja usada como input para o construtor.

Codificação feliz.


1 Isso não tem um nome bonitinho no SLS, mas aqui estão os detalhes. O importante é que ele mude como o Scala liga os argumentos ao método com parâmetros repetidos (como denotado com o Node* acima).

A anotação tipo _* é abordada em “4.6.2 parameters repetidos” do SLS.

O último parâmetro de valor de uma seção de parâmetro pode ser sufixo por “*”, por exemplo, (…, x: T *). O tipo de um parâmetro repetido dentro do método é então o tipo de seqüência scala.Seq [T]. Métodos com parâmetros repetidos T * obtém um número variável de argumentos do tipo T. Isto é, se um método m com tipo (p1: T1,.., Pn: Tn, ps: S *) U é aplicado aos argumentos (e1, .e, ek) onde k> = n, então m é tomadas naquela aplicação para ter tipo (p1: T1, …, pn: Tn, ps: S, …, ps0S) U, com k ¡n ocorrências do tipo S onde qualquer nome de parâmetro além de ps é novo. A única exceção a essa regra é se o último argumento for marcado como um argumento de seqüência por meio de uma anotação de tipo _ *. Se m acima for aplicado aos argumentos (e1, …, en, e0: _ *), então o tipo de m nessa aplicação é considerado como sendo (p1: T1, …, pn: Tn, ps: scala Seq [S]

  • child ++ newChild – sequência
  • : – digite ascription, uma dica que ajuda o compilador a entender, que tipo essa expressão tem
  • _* – espaço reservado aceitando qualquer valor + operador vararg

child ++ newChild : _* expande Seq[Node] para Node* (diz ao compilador que estamos trabalhando bastante com varargs, do que com uma sequência). Particularmente útil para os methods que podem aceitar apenas varargs.

Toda a resposta acima parece ótima, mas só precisa de uma amostra para explicar isso. Aqui está :

 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]* 

Então, agora sabemos o que :_* do é dizer ao compilador: por favor, descompacte este argumento e ligue esses elementos ao parâmetro vararg na chamada de function, em vez de tomar o x como um único argumento.

Então, em poucas palavras, o :_* é para remover ambiguidade quando passar argumento para o parâmetro vararg.

Intereting Posts