web-dev-qa-db-ja.com

Scalaで `:_ *`(コロンアンダースコアスター)は何をしますか?

この質問 からの次のコードがあります:

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と連結してから、? : _* 行う?

182
amorfis

それは「スプラット」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にはcutesy-nameがありませんが、詳細は次のとおりです。取得する重要なことは、Scalaが上記のNode*で示されるように、繰り返しパラメーターを使用してメソッドに引数をバインドする方法を変更することです。

_* type注釈は、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])

142
user166390
  • child ++ newChild-シーケンス
  • :-型の説明、コンパイラが理解するのに役立つヒント、その式にはどの型があるのか
  • _*-任意の値を受け入れるプレースホルダー+可変引数演算子

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

86
Vasil Remeniuk

上記の答えはすべて素晴らしく見えますが、これを説明するにはサンプルが必要です。ここにあります :

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

これで、:_* doはコンパイラに指示することです。xを単一の引数として受け取るのではなく、この引数をアンパックして、関数呼び出しでこれらの要素をvarargパラメーターにバインドしてください。

つまり、:_*は、引数をvarargパラメーターに渡すときにあいまいさを取り除くためのものです。

18
Keith