web-dev-qa-db-ja.com

Scalaの '::'演算子、それはどのように機能しますか?

Scalaでは、ケースクラスcase class Foo(x:Int)を作成して、次のようにリストに入れることができます。

List(Foo(42))

ここで、奇妙なことは何もありません。以下は私には奇妙です。演算子::はリストの関数ですよね? Scalaの引数が1つの関数であれば、中置記法で呼び出すことができます。たとえば、1 + 2は、オブジェクトIntに対する関数(+)です。先ほど定義したクラスFooには::演算子がないので、次のようにするにはどうすればよいですか?

Foo(40) :: List(Foo(2))

Scala 2.8 RC1で、インタラクティブプロンプトから次の出力を取得します。

scala> case class Foo(x:Int)
defined class Foo

scala> Foo(40) :: List(Foo(2))
res2: List[Foo] = List(Foo(40), Foo(2))

続けて使うことはできますが、その説明は?

54
Felix

仕様から:

6.12.3 InfixOperations infix演算子は任意の識別子にすることができます。中置演算子には、次のように定義された優先順位と結合規則があります。

...

演算子の関連性は、演算子の最後の文字によって決まります。コロン「:」で終わる演算子は右結合です。他のすべての演算子は左結合です。

Scala=)でこれらのルールがどのように適用されるかは、コンパイラの 'typer'フェーズを通過した後にプログラムを印刷することで常に確認できます。

scala -Xprint:typer -e "1 :: Nil"

val r: List[Int] = {
  <synthetic> val x$1: Int = 1;
  immutable.this.Nil.::[Int](x$1)
};
48
retronym

_:_で終わります。そして、それは、この関数が右側のクラス(ここではListクラス)で定義されていることを示しています。

したがって、例ではList(Foo(2)).::(Foo(40))ではなくFoo(40).::(List(Foo(2)))です。

21
folone

指定された回答に欠けている1つの側面は、パターンマッチング式で_::_をサポートすることです。

_List(1,2) match {
  case x :: xs => println(x + " " + xs)
  case _ => println("")
}
_

クラス::が定義されています

_final case class ::[B](private var hd: B, private[scala] var tl: List[B]) 
_

したがって、case ::(x,xs)も同じ結果になります。式_case x :: xs_が機能するのは、デフォルトの抽出子_::_がケースクラスに定義されており、インフィックスで使用できるためです。

17
Thomas Jung

先ほど定義したクラスFooには_::_演算子がないため、次のようにすることができます。

Foo(40) :: List(Foo(2))

メソッド名がコロン(_:_)で終わっている場合、メソッドは右側のオペランドで呼び出されます。メソッド名がコロンで終わらない場合、メソッドは左側のオペランドで呼び出されます。たとえば、_a + b_、_+_はaで呼び出されます。

したがって、あなたの例では、_::_はその右側のオペランドのメソッドであり、Listです。

15