Що робить `: _ *` (зірка підкреслення двокрапки) у Scala?


195

У мене є наступний фрагмент коду з цього питання :

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, і тоді? Що робить : _*?


70
Дякую вам за додавання (зірка підкреслення товстої кишки) до назви!
Гал

Відповіді:


151

Він "заплескає" 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*зазначено вище).

_*Тип анотації покрита «4.6.2 Повторні параметри» СЛС.

Останнє значення параметра розділу розділу може бути задано символом «*», наприклад (..., x: T *). Тип такого повторного параметра всередині методу - це тип послідовності scala.Seq [T]. Методи з повторними параметрами T * приймають змінну кількість аргументів типу T. Тобто, якщо метод m з типом (p1: T1,., Pn: Tn, ps: S *) U застосовується до аргументів (e1, ..., ek), де k> = n, то m дорівнює прийнято у цій програмі мати тип (p1: T1,.Винятком з цього правила є те, якщо останній аргумент позначений як аргумент послідовності за допомогою анотації типу _ *. Якщо m вище застосовується до аргументів (e1, ..., en, e0: _ *), то тип m у цій програмі вважається рівним (p1: T1,.., Pn: Tn, ps: scala .Seq [S])


5
Ми любимо називати це "оператором Smooch", хоча це насправді не оператор :)
Генрік Густафссон

1
У Python це називається розпаковуванням
joshlk

Чи є обмеження на тривалість такої послідовності, як, наприклад, з Java-вараггами?
qwwqwwq

95
  • child ++ newChild - послідовність
  • : - тип атрибуції, підказка, яка допомагає компілятору зрозуміти, який тип має це вираження
  • _* - заповнювач заповнення, який приймає будь-яке значення + оператор vararg

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


1
Не могли б ви написати більше про "тип підписки"? Що це таке і як це працює?
amorfis


24

Всі вищевказані відповіді виглядають чудово, але просто потрібен зразок для пояснення цього. Ось :

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

Отже, тепер ми знаємо, що :_*робити, щоб сказати компілятору: будь ласка, розпакуйте цей аргумент і прив’яжіть ці елементи до параметра vararg у виклику функції, а не приймайте x як єдиний аргумент.

Отже, у двох словах, :_*полягає у видаленні неоднозначності при передачі аргументу параметру vararg.


5

Для деяких таких ледачих людей, як я, це просто перетворює Seq у varArgs!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.