¿Qué hace`: * ' (estrella de subrayado de dos puntos) en Scala?


Tengo el siguiente fragmento de código de esta pregunta :

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

Todo está bastante claro, excepto esta pieza: child ++ newChild : _*

¿Qué hace?

Entiendo que hay Seq[Node] concatenado con otro Node, y entonces? ¿Qué hace : _*?

Author: philantrovert, 2011-05-19

3 answers

Se "salpica"1 la secuencia.

Mira la firma del constructor

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

Que se llama como

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

Pero aquí solo hay una secuencia, no child1, child2, etc. así que esto permite que la secuencia de resultados para ser utilizado como la entrada para el constructor.

Feliz codificación.


1 Esto no tiene un nombre cursi en el SLS, pero aquí están los detalles. Lo importante es que cambie la forma en que Scala une los argumentos al método con parámetros repetidos (como se indica con Node* anterior).

El _* la anotación de tipo está cubierta en "4.6.2 Parámetros repetidos" del SLS.

El último parámetro de valor de una sección de parámetros puede ser sufijo por"*", por ejemplo (..., x: T *). El tipo de un parámetro repetido dentro del método es entonces el tipo de secuencia scala.Seq[T]. Métodos con parámetros repetidos T * take número variable de argumentos de tipo T . Es decir, si un método m con tipo (p1: T1, . . . ,pn : Tn, ps : S*) U se aplica a los argumentos (e1, . . . , ek) donde k > = n, entonces m se toma en esa aplicación para tener tipo (p1: T1, . . . ,pn : Tn, ps: S, . . . , ps0S) U, con k ¡n ocurrencias de tipo S donde cualquier nombre de parámetro más allá de ps son fresco. La única excepción a esta regla es si el último argumento está marcado como un argumento de secuencia a través de una anotación de tipo_*. Si m anterior se aplica a los argumentos (e1, . . . , en, e0:_*), luego el tipo de m en esa aplicación se toma como (p1: T1, . . . ,pn : Tn, ps :scala.Seq [S])

 124
Author: Roman Kagan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-02-08 00:25:03
  • child ++ newChild - secuencia
  • : - type ascription, una sugerencia que ayuda al compilador a entender, qué tipo tiene esa expresión
  • _* - marcador de posición que acepta cualquier valor + operador vararg

child ++ newChild : _* expande Seq[Node] a Node* (le dice al compilador que estamos trabajando más bien con un varargs que con una secuencia). Particularmente útil para los métodos que solo pueden aceptar varargs.

 78
Author: Vasil Remeniuk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-05-18 22:05:59

Toda la respuesta anterior se ve muy bien, pero solo necesita una muestra para explicar esto . Aquí 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]*

Así que ahora sabemos lo que :_* hace es decirle al compilador : por favor desempaquetar este argumento y enlazar esos elementos al parámetro vararg en la llamada a la función en lugar de tomar la x como un solo argumento .

Así que en pocas palabras, el :_* es eliminar la ambigüedad cuando pase el argumento al parámetro vararg.

 2
Author: Keith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-06 06:40:24