Cosa fa `: _ *` (stella di sottolineatura dei due punti) in Scala?


196

Ho il seguente pezzo di codice da questa domanda :

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

Tutto in esso è abbastanza chiaro, tranne questo pezzo: child ++ newChild : _*

Che cosa fa?

Capisco che ci sia Seq[Node]concatenato con un altro Node, e poi? Cosa fa : _*?


70
Grazie mille per l'aggiunta (stella di sottolineatura dei due punti) al titolo!
Gal

Risposte:


152

"Splats" 1 la sequenza.

Guarda la firma del costruttore

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

che si chiama come

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

ma qui c'è solo una sequenza, no child1, child2ecc., quindi ciò consente di utilizzare la sequenza di risultati come input per il costruttore.

Buona codifica.


1 Questo non ha un nome carino in SLS, ma ecco i dettagli. La cosa importante da ottenere è che cambia il modo in cui Scala lega gli argomenti al metodo con parametri ripetuti (come indicato Node*sopra).

L' _*annotazione del tipo è trattata in "4.6.2 Parametri ripetuti" di SLS.

L'ultimo parametro di valore di una sezione di parametri può essere sostituito da “*”, ad es. (..., x: T *). Il tipo di tale parametro ripetuto all'interno del metodo è quindi il tipo di sequenza scala.Seq [T]. I metodi con parametri ripetuti T * accettano un numero variabile di argomenti di tipo T. Cioè, se un metodo m con tipo (p1: T1,..., Pn: Tn, ps: S *) U viene applicato agli argomenti (e1,..., Ek) dove k> = n, allora m è preso in quella applicazione per avere tipo (p1: T1,..., pn: Tn, ps: S,..., ps0S) U, con k ¡n occorrenze di tipo S in cui tutti i nomi dei parametri oltre ps sono freschi.L'unica eccezione a questa regola è se l'ultimo argomento è contrassegnato come argomento della sequenza tramite un'annotazione di tipo _ *. Se m sopra è applicato agli argomenti (e1,..., En, e0: _ *), allora si considera che il tipo di m in quella applicazione sia (p1: T1,..., Pn: Tn, ps: scala .seq [S])


5
Ci piace chiamarlo "operatore Smooch", anche se in realtà non è un operatore :)
Henrik Gustafsson,

1
In Python questo si chiama
unpacking

Esiste un limite a quanto può durare la sequenza, ad esempio con varargs Java?
qwwqwwq,

95
  • child ++ newChild - sequenza
  • : - digitare ascrizione, un suggerimento che aiuta il compilatore a capire, che tipo ha quell'espressione
  • _* - segnaposto che accetta qualsiasi valore + operatore vararg

child ++ newChild : _*si espande Seq[Node]in Node*(dice al compilatore che stiamo piuttosto lavorando con un varargs, piuttosto che una sequenza). Particolarmente utile per i metodi che possono accettare solo varargs.


1
Potresti scrivere di più su "type ascription"? Che cos'è e come funziona?
amorfis,


24

Tutta la risposta di cui sopra sembra ottima, ma serve solo un campione per spiegarlo. Ecco qui :

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

Quindi ora sappiamo cosa :_*fare è dire al compilatore: decomprimere questo argomento e associare quegli elementi al parametro vararg nella funzione call piuttosto che prendere x come singolo argomento.

Quindi, in breve, :_*è rimuovere l'ambiguità quando si passa l'argomento al parametro vararg.


5

Per alcune persone pigre come me, converte un Seq in varArgs!

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.