sekikatsu
@sekikatsu

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

Scalaでobjectを実行時初期化する方法

Q&A

Closed

scalaでシングルトンオブジェクトを初期化する方法がわからず、ご相談させてください。
例えばSample.xxxとアクセスすると、初回アクセスのみxxxの初期化処理が走り、その後は初期化済みの値が読み込めるようにしたいです。

例えば、Javaと同じように、シングルトンではなくコンパニオンオブジェクトを経由させて、privateコンストラクタとsingleton用フィールドを使えば、以下のように実現が可能でした。

class Sample private (val xxx: Int, val yyy: Int) {
}
object Sample {
  val singleton: Sample = {
    val zzz: Int = //実行時に決定する値
    val xxx = if (zzz > 0) 1 else 0;
    val yyy = if (zzz > 10) 1 else 0;
    new Sample(xxx, yyy)
  }
}

しかし、この場合はSample.singleton.xxx という形でアクセスする必要があります。
scalaにはせっかくobjectがあるので、Sample.xxxとアクセスしたいのですが、実現方法がわかりませんでした。

もちろん、以下のような実装は可能ですが、コード量が増え、あまりキレイでないので、scalaならもっと良い方法があるのではないかと思っています。

var initialized = false
var _xxx
def xxx() {
  if(!initialized) {
    initialized = true
    _xxx = //初期化
  }
  _xxx
}

何か思いつく方法はありますでしょうか。

0

2Answer

シンタックスハイライトが効かないので新しく投稿します。

遅延初期化用のクラスをつくるのは良さそうですね。次のような感じでしょうか。


object Sample {
  private lazy val hoge = new Hoge
  
  lazy val xxx = hoge.xxx
  lazy val yyy = hoge.yyy
}

class Hoge {
  println("initialized")
  val xxx = "xxx"
  val yyy = "yyy"
}

println("start")
println(Sample.xxx)
println(Sample.yyy)
start
initialized
xxx
yyy
1Like

Comments

  1. @sekikatsu

    Questioner

    なるほど、Hogeクラスのに直接初期化処理を書けばいけそうです!
    下手に初期化処理をメソッドでまとめてしまうと、うまく動かなそうでした。
    ありがとうございます!
  2. 直接というか上のはコンストラクタですね。

遅延初期化の利用を検討してみてはいかがでしょうか。

object Sample {
  lazy val xxx = {
    println("initialized")
    "xxx"
  }
}

println("start")
println(Sample.xxx)
println(Sample.xxx)
start
initialized
xxx
xxx
0Like

Comments

  1. @sekikatsu

    Questioner

    回答ありがとうございます!
    遅延初期化を使えば、xxxの単独の初期化は行えそうです。

    しかし、今回は`xxx`と`yyy`の初期化を同時に行いたく、その場合の実装方法がわかりませんでした。

    xxxとyyyをまとめたクラスを作って、単独で遅延初期化しようとしましたが、できませんでした。。。

    ## 案1

    ```scala
    object Sample {
    lazy val hoge = new Hoge
    }
    class Hoge {
    var xxx = -1
    var yyy = -1

    def apply: Hoge = {
    val result = new Hoge
    xxx = 1
    result.xxx = 2
    yyy = 1
    result.yyy = 2
    println("1: xxx = ${xxx}")
    result
    }
    }
    ```

    ```
    println("2: xxx = ${Sample.xxx}")
    // 出力結果 (applyが呼ばれない)
    // 2: xxx = -1
    ```

    ## 案2

    ```scala
    object Sample {
    lazy val hoge = new Hoge
    }
    class Hoge {
    init()
    println("2: xxx = ${xxx}")

    var xxx = -1
    var yyy = -1

    def init(): Unit = {
    xxx = 1
    yyy = 1
    println("1: xxx = ${xxx}")
    }
    }
    ```

    ```
    println("3: xxx = ${Sample.xxx}")
    // 出力結果 (1にセットされたあと-1でリセットされる)
    // 1: xxx = 1
    // 2: xxx = 1
    // 3: xxx = -1
    ```

Your answer might help someone💌