web-dev-qa-db-ja.com

Scalaでparam:_ *はどういう意味ですか?

Scala(2.9.1)が初めてなので、List[Event]があり、それをQueue[Event]にコピーしたいが、次の構文はQueue[List[Event]]代わりに:

val eventQueue = Queue(events)

何らかの理由で、次のように機能します:

val eventQueue = Queue(events : _*)

しかし、私はそれが何をするのか、そしてなぜそれが機能するのかを理解したいと思いますか?私はすでにQueue.apply関数の署名を見ました:

def apply[A](elems: A*)

そして、最初の試みがうまくいかない理由を理解していますが、2番目の試みの意味は何ですか?この場合の:および_*とは何ですか。また、なぜapply関数がIterable[A]を受け取らないのですか?

66
Chris

a: Aはタイプの説明です。 Scalaでの型表記の目的は何ですか を参照してください

: _*は、シーケンス型の単一の引数を可変引数シーケンス、つまりvarargsとして扱うようにコンパイラーに指示する、型表記の特別なインスタンスです。

シーケンスまたは反復可能な単一の要素を持つQueue.applyを使用してQueueを作成することは完全に有効であるため、単一のIterable[A]を指定するとまさにこれが起こります。

72
Ben James

これは、すべての要素を単一の引数としてではなく、独自の引数として渡すようコンパイラーに指示する特別な表記法です。 here を参照してください。

これはシーケンス引数を示す型注釈であり、言語仕様のセクション4.6.2の一般規則の「例外」として言及されています。 「繰り返しパラメータ」。

関数が可変数の引数を取る場合に便利です。 def sum(args: Int*)などの関数は、sum(1)sum(1,2)などとして呼び出すことができます。xs = List(1,2,3)などのリストがある場合、 xsではなくListであるため、Int自体を渡すことはできませんが、sum(xs: _*)を使用してその要素を渡すことができます。

Python人々:

Scalaの_*演算子は、Pythonの *-operator とほぼ同等です。


Luigi Plinge が提供する link のscalaの例を変換)

def echo(args: String*) = 
    for (arg <- args) println(arg)

val arr = Array("What's", "up", "doc?")
echo(arr: _*)

to Pythonは次のようになります。

def echo(*args):
    for arg in args:
        print "%s" % arg

arr = ["What's", "up", "doc?"]
echo(*arr)

両方とも次の出力を提供します。

なに
アップ
doc?


違い:位置パラメータの展開

Pythonの*- operatorは、固定引数関数の位置パラメータ/パラメータのアンパックも処理できます。

def multiply (x, y):
    return x * y

operands = (2, 4)
multiply(*operands)

8

Scalaで同じことを行う:

def multiply(x:Int, y:Int) = {
    x * y;
}

val operands = (2, 4)
multiply (operands : _*)

失敗します:

メソッドの乗算に十分な引数がありません:(x:Int、y:Int)Int。
未指定の値パラメーターy。

しかし、scalaでも同じことを実現できます。

def multiply(x:Int, y:Int) = {
    x*y;
}

val operands = (2, 4)
multiply _ tupled operands

Lorrin Nelson によると、これがどのように機能するかです:

最初の部分f _は、引数が指定されていない部分的に適用された関数の構文です。これは、関数オブジェクトを保持するメカニズムとして機能します。 tupledは、単一のarity-n Tupleを取るarity-1の新しい関数を返します。

さらに読む:

2
Murmel