У меня есть такой код из этого вопроса:
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, а потом? Что делает : _*
?
Он "отображает" 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 Это не имеет cutesy-name в SLS, но вот подробности. Важно то, что он изменяет, как Scala связывает аргументы с методом с повторяющимися параметрами (как указано выше с Node*
).
Аннотации типа _*
описаны в разделе "4.6.2 Повторяющиеся параметры" SLS.
Последний параметр значения секции параметров может быть удовлетворен "*", например. (..., x: T *). Тип такого повторяющегося параметра внутри метода тогда тип последовательности scala.Seq [T]. Методы с повторяющимися параметрами T * принимают переменное количество аргументов типа T. То есть, если метод m с типом (p1: T1,..., pn: Tn, ps: S *) U применяется к аргументам (e1,..., ek), где k >= n, тогда m принимает в этом приложении тип (p1: T1,..., pn: Tn, ps: S,..., ps0S) U, с k ¡n вхождениями типа S, где любые имена параметров за пределами ps свежий. Единственное исключение из этого правила - если последний аргумент отмечен как аргумент последовательности с помощью аннотации типа _ *. Если m применяется к аргументам (e1,..., en, e0: _ *), то тип m в этом приложении принимается как (p1: T1,..., pn: Tn, ps: scala.Seq [S])
child ++ newChild
- последовательность:
- тип ascription, подсказка, которая помогает компилятору понять, какой тип имеет это выражение_*
- заполнитель, принимающий любое значение + оператор vararg child ++ newChild : _*
расширяет Seq[Node]
до Node*
(сообщает компилятору, что мы скорее работаем с varargs, чем последовательность). Особенно полезно для методов, которые могут принимать только varargs.