endless pulse

どっくんどっくんふるえる毎日を過ごしています

Scalaのシングルトンオブジェクトとクラス

Scalaのシングルトンオブジェクトとクラスの使い方について少し苦労したのでそのときのメモを転載。

記法(宣言)

Scalaにはクラス宣言とシングルトンオブジェクトの宣言がある。

class Sample {
  val a = 3
  def hello = {
    println("Hello, World!")
  }
}
object Sample {
  private val b = 4
  val c = 5

  def hello = {
     println("Hello, World again!")
  }
}

Javaを知っている方にはおなじみのクラスの宣言と、下はシングルトンオブジェクトの宣言。両方とも継承があればJavaとかと同じようにextends〜とかつなげればいい。トレイトも宣言時にwith〜とかやると使える。(トレイトについては使い慣れてないのでボロをださない程度の説明にしておきます。。)

同名のクラスとシングルトンオブジェクトが宣言できる。同名のメソッドを中で宣言しても怒られない。
一体この2つの違いは何なの?という話。

シングルトンオブジェクトはJavaでいうstaticなメソッド/フィールドだけのクラス

実はScalaには「static」という予約語はない。
えええー、じゃあ、staticな変数はどうするの?メソッドは?staticなクラスだって作りたいよ〜〜

というののために、シングルトンオブジェクトがある。
さっきの、object Sampleっていう宣言の方。
上記の例で言うと、object Sampleと書いた方はstaticなクラスとして扱える。
だから、外のクラスから、何もnewすることなしに

  Sample.hello

とかやると、JavaのStaticクラスのようにメソッドが扱える。
フィールドも、同じように扱える。上記の例で言うと

とかやると、JavaのStaticなメソッド/フィールドだけを持ったクラスのように扱える。上記の例で言うと

  Sample.c

とやると、cの値である5が得られる。
※ちなみに、このとき c は変数のgetterのメソッドとして呼ばれているらしい。ので実際にはメソッド名を扱ってるだけなのでフィールドの場合とかいう話じゃないです。。
変数をvarで宣言すると、setterメソッドとして

変数名_(代入したい値)

みたいなのが宣言される上に、

変数名 = 代入したい値

でも上記のsetterが呼び出されて代入できる

さらにちなみに、同名のクラスに対してのシングルトンオブジェクトは、コンパニオンオブジェクトと呼ばれ、コンパニオンオブジェクトの中のprivateで宣言されているものに対して、同名のクラスからであればアクセスできる。

ちょっと、「staticなメソッド」あたりを自分がしっかり理解していなかったみたいで、なぜシングルトンオブジェクトからクラスの方の変数が参照するやり方わかんねー!と思っていたけど、要するにthisを扱うのはstaticなメソッドでいられないから…という理解でいいんだよね?

参考にしたもの

※自分がちょっと勘違いしまくりだったので訂正しました。。