param:_ *はScalaで何を意味しますか?


87

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]

回答:


93

a: Aタイプの帰属です。Scalaでの型の帰属の目的は何ですか?を参照してください

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

シーケンスまたは反復可能な単一の要素を持つQueueusingを作成することは完全に有効Queue.applyであるため、これは、単一のを指定したときに発生することとまったく同じですIterable[A]


83

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

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

関数が可変個の引数を取るときには、例えば、Aのような機能に有用であるdef sum(args: Int*)として呼び出すことができ、sum(1)sum(1,2)あなたがリストを持っている場合などなどxs = List(1,2,3)、あなたが渡すことができないxsことがあるので、自分自身をListするのではなくInt、ただし、を使用してその要素を渡すことができますsum(xs: _*)


def sum(xs: _*)'エラー:バインドされていないワイルドカードタイプ'をスローします
7kemZmani 2017

あなたの答えは明らかですが、これは実際には私にとってより混乱を引き起こしています。通常、scalaxs: intではxsの型がintであるxs: _*ことを意味します。これは、上記のscalaの構文であり、xsが個々のメンバーにキャストされることを意味します。
Rpant 2017

上記のリンクをたどると、それが何であるかのように見えます。型の帰属は、Java型キャストのスカラ用語です。間違っていたら訂正してください。
Rpant 2017

1
@ 7kemZmani:特定のvar-argsタイプで関数を定義するdef sum(args: Int*)必要があります:そしてワイルドカード「ジェネリック」var-argsタイプでそれを呼び出します:val a = sum(xs: _*)_*「私はInt *、String *、またはメソッドシグネチャで定義されているもの*を渡しています」と考えてください
Alfonso Nishikawa

10

Pythonの人々のために:

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


Luigi Plingeが提供するリンクからscalaの例を変換する:

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

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

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

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

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

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


アップ
ドキュメントは?


違い:位置パラメータの解凍

Pythonの*演算子は、位置パラメーター/固定アリティ関数のパラメーターのアンパックも処理できます。

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 : _*)

失敗します:

メソッドmultiplyの引数が足りません:(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タプルをとるarity-1の新しい関数を返します。

さらに読む:

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