Что делает`: * ' (colon underscore star) в Scala?


у меня есть следующий фрагмент кода этот вопрос:

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

все в нем довольно ясно, кроме этой части:child ++ newChild : _*

что он делает?

Я так понимаю есть Seq[Node] соединяется с другой Node, а потом? Что значит : _* делать?

3 156

3 ответа:

это "знаки"1 последовательности.

посмотрите на подпись конструктора

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

, которая называется

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

но здесь есть только последовательность, а не child1,child2 и т. д. таким образом, это позволяет использовать результирующую последовательность в качестве входных данных для конструктора.

удачи в кодировании.


1 у этого нет симпатичного имени в SLS, но вот подробности. Главное, чтобы получить это что это меняет, как Scala связывает аргументы с методом с повторяющимися параметрами (как обозначается с Node* выше).

The _* тип аннотации рассматривается в разделе" 4.6.2 повторные параметры " SLS.

последнее значение параметра раздела параметров может быть суффиксом"*", например (..., x:T *). Тип такого повторяющегося параметра внутри метода тогда последовательность типа scala.Seq[T]. Методы с повторением параметры T * take переменное число аргументов типа T . То есть, если метод m с типом (p1 : T1, . . . , pn : Tn,ps: S*)U применяется к аргументам (e1, . . . , ek) где k >= n, то m принимается в этом приложении, чтобы иметь тип (p1: T1, . . . ру : ТН зы : с . . . , ps0S) U, с K ¡ N вхождений типа S, где любые имена параметров за пределами ps являются свежий. единственное исключение из этого правила, если последний аргумент помечен как аргумент последовательности через _* Аннотация типа. Если M выше применяется к аргументам (e1,. . . , en, e0:_*), то тип m в этом приложении принимается равным (p1 : T1, . . . , pn :Tn,ps: scala.Seq[S])

  • child ++ newChild последовательности
  • : - Type ascription, подсказка, которая помогает компилятору понять, какой тип имеет это выражение
  • _* - заполнитель, принимающий любое значение + оператор vararg

child ++ newChild : _* расширяет Seq[Node] до Node* (говорит компилятору, что мы скорее работаем с varargs, чем с последовательностью). Особенно полезно для методов, которые могут принимать только varargs.

все вышеприведенные ответы выглядят великолепно, но просто нужен образец, чтобы объяснить это . Вот это :

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

Итак, теперь мы знаем, что :_* do-это сообщить компилятору: пожалуйста, распакуйте этот аргумент и свяжите эти элементы с параметром vararg в вызове функции, а не принимайте x в качестве одного аргумента .

Итак, в двух словах,:_* убрать двусмысленность, когда аргумент передать параметр с переменным числом аргументов.