読者です 読者をやめる 読者になる 読者になる

夢とガラクタの集積場

落ちこぼれ三流エンジニアである管理人の夢想=『夢』と、潰えた夢=『ガラクタ』の集積場です。

scalaで出来ることを並べてみる:演算子表現=メソッド表現&リッチラッパー

scalaJavaと違って、演算子(+とか)が存在せず、全てメソッドで構成されているとなっています。

なんですが、イマイチそれだけ言われても実感できないので、
試してみました。
ついでにリッチラッパーの確認もやってました。

サンプルコード

■OperatorMethodMain.scala

package jp.gr.kmtn.scalatutorial.grammertips

/**
 * 演算子/メソッド共通確認+リッチラッパー確認テスト用メインクラス
 *
 * @author Fukushi-
 */
object OperatorMethodMain {

  /**
   * 演算子/メソッド共通確認+リッチラッパー確認テスト用プログラムエントリポイント
   */
  def main(args: Array[String]): Unit =
    {
      // 演算子動作確認
      val two = 2
      val five = 5
      val nine = 9

      // 演算子表現確認
      Console.println("---Case 1-1 ---")
      Console.println(two + five)
      Console.println(nine - five)

      // メソッド表現確認
      Console.println("---Case 1-2 ---")
      Console.println(two.+(five))
      Console.println(nine.-(five))

      // メソッド動作確認
      val str = "Two,Five,Nine"

      // 演算子表現確認
      Console.println("---Case 2-1 ---")
      val strArray = str split ","
      strArray.foreach(Console.println(_))

      // メソッド表現確認]
      Console.println("---Case 2-2 ---")
      str.split(",").foreach(Console.println(_))

     
      // リッチラッパー用メソッド確認
      Console.println("---RichWrapper ---")
      Console.println(nine max five)
      Console.println(nine.max(five))
    }

}


実行結果

で、実行結果は下記のようになります。

---Case 1-1 ---
7
4
---Case 1-2 ---
7
4
---Case 2-1 ---
Two
Five
Nine
---Case 2-2 ---
Two
Five
Nine
---RichWrapper ---
9
9


コード解説


上のCase1-Xから見ていきましょう。

Case1-1ではInt型の変数を + で連結して加算を行っています。
Case1-2では、Int型変数のメソッド「+」を呼び出して加算を行っています。

Console.println(two + five) → Case1-1、「+」を演算子形式で記述
Console.println(two.+(five)) → Case1-2、「+」をメソッド形式で記述

Case1-1と、Case1-2の表現は等価です。
つまり、演算子のように見える「+」もメソッドでしかないことがわかりますね。
後、実際にInt型変数のメソッド一覧(Eclipseの補完一覧)を見てみると
演算子と同じメソッドが存在していることがわかります。




次は、Case2-Xの説明です。

Case1-Xとは逆に、splitメソッド演算子形式で記述しています。

val strArray = str split "," → Case2-1、「split」を演算子形式で記述
val printArray = str.split(",") → Case2-2、「split」をメソッド形式で記述

Case2-1、Case2-2の表現も等価です。
つまりはScalaでは下記の2つのことが言える、となりますね。

1.演算子は存在せず、全てメソッドで構成されている

2.メソッドJavaでいう演算子形式と、メソッド形式のどちらでも記述可能


Javaと書き方自体は変えずに、背後で動く機構は統一されているようですね。なかなか新鮮。


後、最後にリッチラッパーについて。
下記のコードで、Int型に対してmaxというメソッドを使用しています。

Console.println(nine max five)
Console.println(nine.max(five))

なんですが、Int型にはmaxというメソッドは存在しません。
maxというメソッドが定義されているのは、「scala.runtime.RichInt」というクラスです。
下記のコードの中で、maxメソッド実行時に暗黙の型変換(Int→RichInt)がおこなわれてるため、
Int型の変数が直接maxメソッドを呼び出せるようです。

どういう仕組みなのかなぁ。。と思ってみてクラス構造を見てみた所、
scala.runtime.ScalaNumberProxy」、「scala.runtime.ScalaNumberProxy」クラスが
リッチラッパーに絡んでいる模様。

更に背後には、「scala.Proxy」トレイトや、「scala.Proxy.Typed」トレイトが絡んでいる模様。
自分で今回のリッチラッパーのように既存のクラスに対して機能を追加できる、
追加機能の実行時にのみ暗黙的に型変換されるため
余計な考慮は不要というコードが作れたら面白そうですよね。

ただ、それについてはまたの機会に。