のーずいだんぷ

主に自分用メモですが、もしかしたら誰かの役に立つかもしれません

Scalaにおけるobject(static)とは

はじめに

私の所属する会社ではコードベースがScalaなのだが、方針としてPythonへ移行することになっているため、今の所ちゃんと書いたことがなくこれまで雰囲気で読んでいた。

Scalaにはcase class のように、Javaや(私が使用できる)他の言語には無い独自の概念が多く、色々と理解が曖昧だと感じているので基礎的なところから徐々に見直して行きたい(Java自体も初心者ではあるが…)

staticとはそもそもなにか

staticは静的/動的型付け関わらず存在する概念で、「クラスが保持する」ことを示す。 なのでstaticメンバといえば、インスタンスではなく、クラス自体が保持するメンバ(プロパティ)であることをを意味する。

Javaにおけるstatic

これは調べるとすぐに色々なサイトで説明があるが、基本的にはメソッドやメンバの宣言前にstatic修飾子をつけることでstaticな要素となる。 例えば以下のような感じだろう。

public class StaticExampleClass(){
static private String value1 = "class_member"
private String value2 = "instance_member"
 
   static public void main(String[] args){
        System.out.println(StaticExampleClass.value1)
        System.out.println(value2) //value2ではインスタンス化していないためこのままでは呼び出せない。
        ins = new StaticExampleClass()
        System.out.println(ins.value2) //インスタンス.メンバでなら呼び出すことができる。
}

上記でメンバvalue1はstaticメンバであり、value2は(staticでない)通常のメンバである。 ちなみにJavaの場合、エントリポイント(コンストラクタ)のメソッドはstatic void main(String[])と書くのが慣例だが、これも実はstaticなメソッドであることがわかる。

またJavaでは以下のようにイニシャライザも以下のようにStaticに定義することもできる。

public class StaticExampleClass(){
static private String value1 = "class_member"
private String value2 = "instance_member"

// staticイニシャライザ
static{
    private String value3 = "initialized_value" 
}
 
   static public void main(String[] args){
        System.out.println(StaticExampleClass.value1)
        System.out.println(value2) //value2ではインスタンス化していないためこのままでは呼び出せない。
        ins = new StaticExampleClass()
        System.out.println(ins.value2) //インスタンス.メンバでなら呼び出すことができる。
}

staticイニシャライザはクラスのプロパティを定義するので、クラスがロードされる際に一度だけ実行される。

Scalaにおけるstatic

まず注意として、Scalaにはstaticという概念はそもそも存在しない。正確にはstatic相当であり、同一の概念ではない。 Scalaの場合にはObjectを使って、インスタンスが一つのみしか存在しないシングルトンオブジェクトを使うことで近い処理を実現している。 ちなみにJavaにもObjectはあるが、これはオブジェクトとしての機能を提供するするための全てのクラスのスーパークラスとしての位置づけなので Scalaのものとは異なるので注意が必要。

objectの基本的な定義方法について以下にまとめる。

  • 宣言はclassと大きく変わらず、objectキーワードで宣言する
  • 基本的にはクラスの宣言と似ているが、コンストラクタ引数をobjectキーワードのあとに持つことはできない
  • lazyの様に遅延評価(アクセスされる際に初めて生成される)
  • mainメソッドを定義すれば、それがエントリポイントとなって実行される
object ExampleObject{
  val num = 1
  val value = "test_value"
  def show(x:Int, y:String): Unit ={
    println(s"x:$x, y:$y")
  }
  def main(args: Array[String]): Unit ={
    show(num, value)
  }
}

一応実行して試してみよう。

$ scala ExampleObject.scala 
x:1, y:test_value

ちなみにObjectと同名のクラスを作成すると、それはコンパニオンオブジェクト(クラスの方はコンパニオンクラス)となるが、 それについてはまた別の記事で取り扱う。

参考

docs.scala-lang.org

http://dwango.github.io/scala_text_previews/trait-tut/object.htmldwango.github.io

www.ne.jp