sohatach's blog

http://github.com/soha

Scalaのcaseクラスとか、Javaから入って躓いたところまとめ

caseクラスやらシングルトンオブジェクトやらコンパニオンオブジェクトやら
Scalaの当初Javaの知識だけでは個人的に理解が難しかった点を自分用にまとめる。

参考
Scalaのクラスとオブジェクト、パターンマッチ
http://www.atmarkit.co.jp/ait/articles/1204/20/news139.html

・シングルトンオブジェクトとは

Scalaでは、staticがないため、Javaでいうstaticメソッドを作るには、
シングルトンオブジェクトというものを使います。
インスタンスのないstaticなメソッドが作れない代わりに
シングルトンのオブジェクトを作成するようです。
作り方は、クラス定義時の「class」の代わりに「object」というキーワードを使用します。

atmarkitのサイトによれば、以下のような例が出ています。

object SampleUtil{
    def hello() = println("hello")
}
 
scala> SampleUtil.hello()
hello

hello()メソッドをインスタンスをnewすることなしに使えているのでポイントですね。

・コンパニオンオブジェクトとは

atmarkitのサイトによれば、
> 「コンパニオンオブジェクト」とは、あるクラスに対して同じスコープ、同じ名前で定義されたシングルトンオブジェクトです。
> classとobjectが同じファイル、同じパッケージの中に、同じ名前で宣言されていれば、それはコンパニオンオブジェクトとなります。

特徴
> コンパニオンクラスのprivateなフィールドやメソッドに対してアクセスができる

class SampleCompanion private (num:Int)
  
object SampleCompanion {
    def apply(num:Int) = {
      new SampleCompanion(num)
    }
}
  
object Main {
    def main(args: Array[String]) = {
        val ins = SampleCompanion(10)
        println(ins)
    }
}

サンプルコードでは、
>val ins = SampleCompanion(10)
にてシングルトンオブジェクトのapplyメソッドを呼び出し、
SampleCompanionクラスのインスタンスを生成しています。(実体は、applyメソッドのnew SampleCompanion(num)の実行)

・applyメソッドとは

>「apply」という名前は特別な意味を持っており、オブジェクトのメソッドを関数を扱うように呼び出せます。
とのこと。
具体的には、上記コンパニオンオブジェクトのサンプルコードの
>SampleCompanion(10)
にて、実際には、
>SampleCompanion.apply(10)
を呼ぶのと同じ意味になるとのことです。結果的に、「SampleCompanion(10)」だけで新しいインスタンスが生成される。

これがScalaでの一般的なインスタンスの生成方法らしいですが、
正直私にはこのやり方の何が嬉しいのかよくわかっていません。
かつてJavaインスタンスを直接newするのではなく、DIコンテナからインスタンスを取得するのが
一般的になったことと似ていたりするのだろうか?

・unapplyメソッドとは

> 「unapply」はインスタンス構成要素を抽出するためのメソッドで、「抽出子」とも呼びます。
> このメソッド定義することで、オブジェクトをcase部分に指定できます。
とのこと。

def matchTest(value:Any) = {
  value match {
    case Apple => println("Apple")
    case Orange("DEKOPON") => println("Orange.name=DEKOPON")
    case _ => println("other")
  }
}

> オブジェクトに「unapply」(もしくは「unapplySeq」)というメソッドを定義した状態で、
> caseにそのオブジェクトを書くと、unapply(もしくは「unapplySeq」)が呼ばれます。
Apple,Orangeそれぞれのunapplyメソッドが呼ばれます。

・caseクラスとは

上記atmarkitのサイトによれば、
> あらかじめ想定されるデフォルト処理を定義した状態でクラスを作成するための仕組み

特徴
> applyが定義されるので、newを使用せずにインスタンス化可能
> caseクラスのコンストラクタ引数は、すべてvalとして扱われる
> toStringやequals、copyなどのメソッドが提供される
> unapplyが定義されるので、パターンマッチで使用することが可能
unapplyメソッドも自動で定義されるとのことです。