Qu’est-ce que `: _ *` (deux-points soulignés écanvas) fait dans Scala?

J’ai le morceau de code suivant de cette question :

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

Tout y est clair, sauf ce morceau: child ++ newChild : _*

Qu’est ce que ça fait?

Je comprends qu’il y a Seq[Node] concaténé avec un autre Node , et alors? Que fait : _* faire?

Il “splat” 1 la séquence.

Regardez la signature du constructeur

 new Elem(prefix: Ssortingng, label: Ssortingng, atsortingbutes: MetaData, scope: NamespaceBinding, child: Node*) 

qui s’appelle comme

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

mais ici, il n’y a qu’une séquence, pas child1 , child2 , etc., ce qui permet d’utiliser la séquence de résultats comme entrée pour le constructeur.

Heureux codage


1 Cela n’a pas de nom dans le SLS, mais voici les détails. L’important est de changer la façon dont Scala lie les arguments à la méthode avec des parameters répétés (comme indiqué par Node* ci-dessus).

L’ annotation de type _* est traitée dans “4.6.2 Paramètres répétés” du SLS.

Le dernier paramètre de valeur d’une section de paramètre peut être complété par «*», par exemple (…, x: T *). Le type d’un tel paramètre répété dans la méthode est alors le type de séquence scala.Seq [T]. Les méthodes avec des parameters répétés T * prennent un nombre variable d’arguments de type T. Autrement dit, si une méthode de type (p1: T1,…, Pn: Tn, ps: S *) U est appliquée aux arguments (e1,…, Ek) où k> = n, alors m est prise dans cette application pour avoir le type (p1: T1,…, pn: Tn, ps: S,..,, ps0S) U, avec k ¡n occurrences de type S où tous les noms de parameters au-delà de ps sont frais. La seule exception à cette règle est si le dernier argument est marqué comme un argument de séquence via une annotation de type _ *. Si m ci-dessus est appliqué aux arguments (e1,…, En, e0: _ *), alors le type de m dans cette application est supposé être (p1: T1,…, Pn: Tn, ps: scala .Seq [S])

  • child ++ newChild – sequence
  • : – tapez ascription, un indice qui aide le compilateur à comprendre, quel type cette expression a
  • _* – espace réservé acceptant toute valeur + opérateur vararg

child ++ newChild : _* étend Seq[Node] à Node* (indique au compilateur que nous travaillons plutôt avec un varargs, qu’avec une séquence). Particulièrement utile pour les méthodes qui ne peuvent accepter que varargs.

Toute la réponse ci-dessus a fière allure, mais juste besoin d’un échantillon pour l’expliquer. C’est ici :

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

Alors maintenant, nous soaps ce que :_* do est de dire au compilateur: veuillez décompresser cet argument et lier ces éléments au paramètre vararg dans l’appel de fonction plutôt que de prendre le x comme un seul argument.

En résumé, le paramètre :_* supprime l’ambiguïté lorsqu’il passe un argument au paramètre vararg.