1. 概要

このチュートリアルでは、いくつかの基本的なScala演算子を見ていきます。 演算子の優先順位と結合性のルールを確認します。

2. メソッドと演算子

Scalaでは、すべての演算子はメソッドです。 演算子自体は、単なる構文糖衣またはメソッドを呼び出すための省略形です。

たとえば、算術加算演算子(+)を見てみましょう。

assert(1 + 2 == 3)

ここでは、記号 + を演算子として使用して、2つの数値を加算します。 + シンボルを使用すると、内部的にScalaは+というメソッドを呼び出します。 ドット表記を使用してメソッド+を呼び出すこともでき、同じ結果が得られます。

assert(1.+(2) == 3)

Scalaのどのメソッドも演算子として使用できます。 たとえば、特定のインデックスの文字を返す StringcharAt()メソッドは、標準のドット表記を使用して呼び出すことができます。

assert("Baeldung".charAt(0) == 'B')

オペレーターとして呼び出すこともできます。

val char = "Baeldung" charAt 0
assert(char == 'B')

算術加算( + )と String.charAt()は、どちらも中置演算子の例です。 中置記法を使用して、少なくとも1つの引数を受け入れる任意のメソッドを呼び出すことができます。

メソッドが複数のパラメーターを受け入れる場合、メソッドを中置記法で使用するには、すべてのパラメーターを括弧のペアの間に入れる必要があります。 たとえば、 String.replace()メソッドは2つのパラメーターを取ります。

assert("Baeldung".replace('g', 'G') == "BaeldunG")

すべての小さなケースgを大文字のGに置き換えました。 括弧を使用して、演算子表記で呼び出すことができます。

val str = "Baeldung" replace ('g', 'G')
assert(str == "BaeldunG")

2.1. 接尾辞と接頭辞の演算子表記

これまで、中置演算子表記の例を見てきました。これは、演算子(またはメソッド)が2つのオペランドの間にあることを意味します。 演算子表記には、接頭辞と接尾辞の2種類があります。

プレフィックス演算子は、オペランドの前に表示されます。 たとえば、 -10 の「」。 すべてのプレフィックス演算子は、名前が付いたメソッドに変換されます単項_

assert(10.unary_- == -10)

接尾辞演算子は、オペランドの後に表示されます。 StringメソッドtoUpperCaseを接尾辞演算子として適用できます。

val strUpperCase = "baeldung" toUpperCase
assert(strUpperCase == "BAELDUNG")

接頭辞演算子と接尾辞演算子はどちらも引数を1つだけ取るため、単項演算子とも呼ばれます。

3. 基本的な演算子

Javaの基本的な演算子はすべて、Scalaでも同じように機能しますが、微妙な違いがいくつかあります。 すべての基本的なタイプのScala演算子を見てみましょう。

3.1. 算術演算子

Scalaには、数値型で使用できる次の算術二項演算子があります。

  • 加算(+)
  • 減算(-)
  • 乗算(*)
  • 分割 (/)
  • 余り(%)

中置演算子表記を使用して、それらすべてを呼び出すことができます。

assert(1 + 2 == 3)
assert(3.1 - 1.0 == 2.1)
assert(2 * 6 == 12)
assert(15 / 6 == 2)
assert(15 % 6 == 3)

さらに、Scalaには、数値が正か負かを示す2つの単項演算子もあります。

  • +(メソッド unary _ +
  • –(メソッド unary _-

+ は数値リテラルを正にし、はリテラルを負にします。

val num = 10
assert(-num == -10)
assert(10 + -num == 0)

単項演算子が指定されていない場合、数値リテラルのデフォルト値は正です。

3.2. 関係演算子

Scalaには5つの関係演算子があります。

  • より大きい(>)
  • 未満(<)
  • 以上(> =)
  • 以下(<=)

上記の関係演算子はすべて、ブール値:に評価されます。

assert(10 < 20 == true) 
assert(10 > 20 == false) 
assert(3.0 >= 2.5 == true) 
assert(3.0 <= 2.5 == false)

さらに、ブール値を反転する単項否定(!)演算子もあります。

assert(!true == false)

3.3. 論理演算子

論理演算子、論理-または( || | )および論理-および( && ) 取ったブール値オペランドと評価ブール値結果。 論理-または、2つのオペランドのいずれかがtrueの場合にのみtrueと評価されます。 論理-両方のオペランドがtrueの場合にのみtrueと評価されます。

assert(true || false == true)
assert(true && false == false)

The && || 短絡演算子です。 これらの演算子を使用した式は、常に両方のオペランドを評価するとは限りません。 左側が結果のみを決定する場合、式の右側は無視されます。

たとえば、&&を使用した式の左側が間違い 、式は常に右辺を評価する必要はありません。 間違い 。 同様に、||の左側ががtrueの場合、値は true であるため、右側は評価されません。

例でそれを見てみましょう &&

def printTrue() : Boolean = {
  println("true");
  true
}

def printFalse() : Boolean = {
  println("false"); 
  false
}
val result1 = printFalse() && printTrue() // only "false" is printed
assert(result1 == false)
val result2 = printTrue() && printFalse() // "true" and "false" are printed
assert(result2 == false)

最初の例では、式の結果を決定するのに十分だったため、左側のみが評価されます。 printFalseメソッドはfalseを返すため、右側を評価する必要はありません。

ただし、2番目の例では、printTrueメソッドがtrueを返すため、式の両側が評価され、最終結果を決定するには、右辺の値を知る必要があります。側。

式の両側を評価する場合は、次を使用できます。 | 代わりは。

val result3 = printFalse() & printTrue()  // "false" and "true" are printed
assert(result3 == false)

ご覧のとおり、 式の両側を評価し、短絡しません。

3.4. ビット演算子

ビット演算子は、整数データ型の個々のビットに対して演算を実行します。 Scalaには次のビット演算子があります。

  • ビット単位-または(|)
  • ビット単位-および(&)
  • ビット単位のxor(^)
  • 単項ビット単位の補集合(〜)

それぞれが個々のビットに対して操作を実行します。

val bitwiseAndResult = 2 & 6
assert(bitwiseAndResult == 2)

ビット単位で実行します-そして、2(0010)と6(0110)の各ビットに対して、2(0010)と評価されます。 同様に、 | ^は、それぞれビット単位の論理和とビット単位の排他的論理和を実行します。

は、trueからfalseに、またはその逆に、すべてのビットを反転します。

assert(~2 == -3)

Scalaには、整数データ型に関する3つのシフト方法もあります。

  • 左シフト(<<)
  • 右シフト(>>)
  • unsigned-shift-right(> >>)

すべてのシフト演算子は、左のオペランドの整数値を、右のオペランドの値で指定された量だけシフトします。 Shift-leftは、ビットを左にシフトし、右にゼロを埋めます。

assert(2 << 2 == 8)

ここでは、2(0010)を左に2回シフトして、8(1000)を生成します。

Shift-rightとunsigned-shift-rightはどちらも、ビットを右にシフトします。 Shift-rightは、シフト時に左側の値の最上位ビット(signed-bit)で埋められますが、unsigned-shift-rightはゼロで埋められます。

assert(-8 >> 2 == -2)

-バイナリの-8は11111111111111111111111111111000です。 ここでは、ビットを右に2回シフトし、負の符号付きビットで位置を埋めています。これは1です。 結果は-2(11111111111111111111111111111110)になります。

assert(-8 >>> 2 == 1073741822)

unsigned-shift-rightは、shift-rightとは異なり、シフト時にビットを0で埋めます。 左に-8(11111111111111111111111111111000)を2回シフトすると、1073741822(00111111111111111111111111111110)が生成されます。

3.5. 等式演算子

Scalaでは、==を使用して2つのオブジェクトが等しいかどうかをチェックします。 !=不等式をチェックします。 Javaとは異なり、Scalaのでは、==を使用して、基本タイプだけでなく、すべてのオブジェクトの同等性をチェックできます。

4. 演算子の優先順位

式に複数の演算子が存在する場合、それらは演算子の優先順位に基づいて評価されます。

たとえば、2 + 3 * 6は30ではなく20と評価されます。これは、乗算(*)演算子が加算(+)よりも優先されるため、乗算が最初に実行されるためです。

Scalaの演算子は単なるメソッドであるため、優先順位は、演算子表記で使用されるメソッドの最初の文字の優先順位によって計算されます。

(all other special characters)
* / %
+ -
:
=!
< >
&
^
|
(all letters)

上記の表のメソッドの最初の文字が高いほど、優先度が高くなります。 最初の文字が同じレベルにある場合、評価の順序は左から右になります。

assert(2 + 3 * 4 == 14)

ここで、評価の順序は2 +(3 * 4)であり、*の優先順位が高く、結果として14になります。

assert(4 - 2 + 1 == 3)

+と–は優先順位が同じであるため、評価の順序は左から右、つまり(4 – 2)+1です。

優先ルールには1つの例外があります。 演算子が等しい文字(=)で終わり、比較演算子の1つではない場合(<=、=>、==、!=)、優先順位は単純な割り当て(=)と同じです。

var num = 10
num += 2 * 10
assert(num == 30)

評価の順序はnum+ =(2 * 10)です。 +==と同じ優先順位を持ち、乗算(*)を下回っています。

5. 演算子の結合性

同じ優先順位を持つ複数の演算子が式に表示される場合、結合法則によって演算子のグループ化方法が決まります。 メソッドの最後の文字が結合性を決定します。

「:」文字で終わるメソッドは、左のオペランドを右のオペランドに渡すことによって呼び出されます。 他の文字で終わるメソッドは反対で、右のオペランドが左のオペランドに渡されます。

assert(2 * 3 == 6)

ここで、結合性は 2. *(3)です。 Listメソッド:::の結合法則を見てみましょう、

assert(List(1,2) ::: List(3) == List(1, 2, 3))

この場合、結合性が変化し、 List(3)。:::( List(1,2)):として評価されます。

assert(List(3).:::(List(1,2)) == List(1, 2, 3))

6. 結論

この記事では、Scalaのすべての演算子がどのように単なるメソッドであるかを見てきました。 Scalaのすべての基本的な演算子を調べ、それらの優先順位と結合法則について学びました。

いつものように、すべてのコード例はGitHubにあります。