teclado ingles guion escribir escribe computadora como bajo arroba scala pattern-matching

scala - ingles - guion bajo teclado



¿Qué hace `:_*`(coma de guión bajo) en Scala? (3)

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 en él es bastante claro, excepto esta pieza: child ++ newChild : _*

¿Qué hace?

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


"Splats" 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 , child1 , etc. por lo que esto permite que la secuencia de resultados se use como 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 cambia la forma en que Scala vincula los argumentos al método con parámetros repetidos (como se indica con el Node* arriba).

La anotación de tipo _* se trata en "4.6.2 Parámetros repetidos" del SLS.

El último parámetro de valor de una sección de parámetro puede ser sufijado por "*", por ejemplo (..., x: T *). El tipo de dicho parámetro repetido dentro del método es entonces el tipo de secuencia scala.Seq [T]. Los métodos con parámetros repetidos T * toman una cantidad 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 es tomado en esa aplicación para tener el tipo (p1: T1, ..., pn: Tn, ps: S, ..., ps0S) U, con k en ocurrencias de tipo S donde los nombres de parámetros más allá de ps son nuevos. 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 _ * type. Si m arriba se aplica a argumentos (e1,.., En, e0: _ *), entonces el tipo de m en esa aplicación se toma como (p1: T1, ..., pn: Tn, ps: scala .Seq [S])


Toda la respuesta anterior se ve genial, 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 qué :_* do es decirle al compilador: por favor, descomprima este argumento y vincule esos elementos al parámetro vararg en la llamada a la función en lugar de tomar la x como un único argumento.

Entonces, en pocas palabras, el :_* es para eliminar la ambigüedad cuando se pasa el argumento al parámetro vararg.


  • child ++ newChild - secuencia
  • : - escriba adscripción, una sugerencia que ayuda al compilador a comprender, qué tipo tiene esa expresión
  • _* - marcador de posición que acepta cualquier operador value + vararg

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