Scala では、クラスのほかに、object キーワードを使うことでシングルトンオブジェクトを作ることができる。シングルトンオブジェクトは、クラスとは違ってインスタンス化せずにそのまま使えるオブジェクトだ。
使い道としては次の2つがあげられる。
- ユーティリティメソッドやグローバルな状態の置き場
- 同名クラスのインスタンスのファクトリメソッド
まず、1つ目の使い道を見てみよう。シングルトンオブジェクトの定義構文はクラスの定義とほぼ同じで、class キーワードの代わりに object キーワードを使う。
scala> object Foo { | def hello(): Unit = println("Hello, World!") | } defined object Foo
この例では使っていないけど、クラスやトレイトを継承することもできる。そしてこの Foo オブジェクトはインスタンス化することなくそのまま使うことができる。
scala> Foo.hello Hello, World!
もう1つの使い道、ファクトリメソッドについても見てみよう。同名のクラス Point をシングルトンオブジェクト Point を定義する。
scala> class Point(val x: Int, val y: Int) { | override def toString(): String = "(" + x + ", " + y + ")" | } defined class Point scala> object Point { | def apply(x: Int, y: Int): Point = new Point(x, y) | } defined object Point warning: previously defined class Point is not a companion to object Point. Companions must be defined together; you may wish to use :paste mode for this.
警告が出ているけどとりあえずわきに置いておく。
シングルトンオブジェクトの apply というメソッドは Scala によって特別扱いされ、Point(x, y) という記述があったときに Point.apply(x, y) と解釈される。つまり、Point クラスのインスタンスを作るのに、new Point(2, 3) とする代わりにシングルトンオブジェクトを使って Point(2, 3) とすることができる。試してみよう。
scala> val p = Point(2, 3) p: Point = (2, 3) scala> p.toString res1: String = (2, 3)
ちなみに toString というメソッドはどんなクラスにも定義されているらしい。上の Point クラスは、明示的には何も継承していないけど暗黙に何かのクラスを継承していて(たぶん)、そのクラスで toString メソッドが定義されているので、override キーワードを使って再定義している。
toString メソッドをオーバーライドすると、REPL のレスポンスに現れる値の表示も変わって (2, 3) となる。これは REPL が値を表示するのに、暗黙に toString を呼び出しているからだね(たぶん)。