Co robi `: _ *` (gwiazda dwukropka) w Scali?


195

Mam następujący fragment kodu z tego pytania :

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

Wszystko w nim jest dość jasne, z wyjątkiem tego kawałka: child ++ newChild : _*

Co to robi?

Rozumiem, że istnieje Seq[Node]powiązanie z innym Node, a następnie? Co ma : _*zrobić?


70
Bardzo dziękuję za dodanie (tytułu podkreślenia dwukropka) do tytułu!
Gal

Odpowiedzi:


151

To „splats” 1 sekwencję.

Spójrz na podpis konstruktora

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

który nazywa się jako

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

ale tutaj jest tylko sekwencja, nie child1, child2itp więc pozwala to sekwencja wynik zostać wykorzystane jako wejście do konstruktora.

Szczęśliwego kodowania.


1 To nie ma uroczej nazwy w SLS, ale oto szczegóły. Ważną rzeczą do uzyskania jest to, że zmienia sposób, w jaki Scala wiąże argumenty z metodą z powtarzanymi parametrami (jak Node*wskazano powyżej).

_*Typ adnotacji jest pokryta „4.6.2 Powtarzające parametry” SLS.

Ostatni parametr wartości sekcji parametru może być uzupełniony przez „*”, np. (..., x: T *). Typem takiego powtarzanego parametru w metodzie jest zatem typ sekwencji scala.Seq [T]. Metody z powtarzanymi parametrami T * przyjmują zmienną liczbę argumentów typu T. To znaczy, jeśli metoda m z typem (p1: T1,.., Pn: Tn, ps: S *) U jest stosowana do argumentów (e1,.., Ek), gdzie k> = n, to m jest wzięte w tej aplikacji, aby mieć typ (p1: T1,., pn: Tn, ps: S,.., ps0S) U, z k ¡n wystąpieniami typu S, gdzie nazwy parametrów poza ps są świeże.Jedynym wyjątkiem od tej reguły jest to, że ostatni argument jest oznaczony jako argument sekwencji za pomocą adnotacji typu _ *. Jeśli m powyżej stosuje się do argumentów (e1,.., En, e0: _ *), wówczas przyjmuje się, że typ m w tej aplikacji to (p1: T1,.., Pn: Tn, ps: scala .Seq [S])


5
Lubimy to nazywać „operatorem Smooch”, mimo że tak naprawdę nie jest operatorem :)
Henrik Gustafsson

1
W Pythonie nazywa się to rozpakowywaniem
joshlk

Czy istnieje limit długości sekwencji, na przykład w przypadku varargs Java?
qwwqwwq

95
  • child ++ newChild - sekwencja
  • : - type ascription, wskazówka, która pomaga kompilatorowi zrozumieć, jaki typ ma to wyrażenie
  • _* - symbol zastępczy akceptujący dowolną wartość + operator vararg

child ++ newChild : _*rozwija się Seq[Node]do Node*(mówi kompilatorowi, że raczej pracujemy z varargs niż z sekwencją). Szczególnie przydatny w metodach, które mogą akceptować tylko varargs.


1
Czy możesz napisać więcej o „przypisaniu typu”? Co to jest i jak działa?
amorfis


24

Wszystkie powyższe odpowiedzi wyglądają świetnie, ale wystarczy próbka, aby to wyjaśnić. Oto on:

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

Teraz wiemy, co :_*należy powiedzieć kompilatorowi: rozpakuj ten argument i powiąż te elementy z parametrem vararg w wywołaniu funkcji, zamiast traktować x jako pojedynczy argument.

Krótko mówiąc, :_*ma to na celu usunięcie niejednoznaczności podczas przekazywania argumentu do parametru vararg.


5

Dla niektórych leniwych ludzi, takich jak ja, konwertuje Seq na varArgs!

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.