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
タイトルに(コロンアンダースコアスター)を追加していただき、ありがとうございます。
Gal

回答:


151

シーケンスを「スプラット」1します。

コンストラクタの署名を見てください

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

と呼ばれる

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

しかし、ここでの唯一のシーケンスは、存在しないchild1child2など、これは結果シーケンスはコンストラクタへの入力として使用することができます。

ハッピーコーディング。


1 SLSにはかわいらしい名前はありませんが、詳細は次のとおりです。取得する重要なことは、Scalaが(Node*上記で示したように)パラメーターが繰り返されるメソッドに引数をバインドする方法を変更することです。

_*型注釈は、 SLSの「4.6.2繰り返しパラメータ」で覆われています。

パラメータセクションの最後の値のパラメータには、「*」を付けることができます(例:(...、x:T *))。メソッド内のそのような繰り返しパラメーターの型は、シーケンス型scala.Seq [T]です。繰り返しパラメーターT *を持つメソッドは、タイプTの可変数の引数を取ります。つまり、タイプ(p1:T1、。。。、pn:Tn、ps:S *)Uのメソッドmが引数(e1、。。。、ek)に適用され、ここでk> = nの場合、mはそのアプリケーションでは、タイプ(p1:T1 、.。。、pn:Tn、ps:S 、.。。、ps0S)Uを持ち、psを超えるパラメーター名が新しいタイプSのk¡この規則の唯一の例外は、最後の引数が_ *型注釈を介してシーケンス引数であるとマークされている場合です。上記のmが引数(e1、。。。、en、e0:_ *)に適用されている場合、そのアプリケーションのmのタイプは(p1:T1、。。。、pn:Tn、ps:scalaであると解釈されます。 .Seq [S])


5
実際には演算子ではありませんが、 "スモーチ演算子"と呼びます:)
Henrik Gustafsson

1
Pythonでは、これは解凍と呼ばれます
joshlk '

Java varargの場合のように、シーケンスの長さに制限はありますか?
qwwqwwq 2017年

95
  • child ++ newChild -シーケンス
  • : -タイプサブスクリプション、コンパイラが理解するのに役立つヒント、その式のタイプ
  • _* -任意の値を受け入れるプレースホルダー+可変引数演算子

child ++ newChild : _*に拡張さSeq[Node]れますNode*(シーケンスではなく可変引数で作業していることをコンパイラーに伝えます)。可変引数のみを受け入れることができるメソッドに特に役立ちます。


1
「type ascription」について詳しく教えてください。それは何で、どのように機能しますか?
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]*

これで、:_*コンパイラに何をするかがわかりました。この引数をアンパックして、xを単一の引数としてとるのではなく、関数呼び出しでそれらの要素をvarargパラメータにバインドしてください。

つまり、簡単に言えば、:_*引数をvarargパラメータに渡すときに曖昧さを取り除くことです。


5

私のような怠惰な人々の一部にとって、それはSeqをvarArgsに変換するだけです!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.