Как инициализировать vals объекта со значениями, известными только во время выполнения?

Скажем, я пытаюсь написать простую игру Tic-Tac-Toe. Он имеет поле M x N. В игре есть только одно поле, поэтому он, вероятно, должен быть представлен синглом object. Вот так:

object Field {
    val height : Int = 20
    val width : Int = 15
    ...
}

Но я не хочу жестко задавать высоту и ширину, поэтому было бы неплохо, если бы они могли быть переданы объекту во время выполнения, через конструктор или что-то в этом роде. Но object не может иметь конструкторов.

Ну, я мог бы изменить height и width как var s, а не val и ввести новый метод

def reconfigure (h:Int, w:Int) = {
    height = h
    width = w
}

и назовите его в начале игры. Но это тоже не изящно.

Итак, есть ли опрятный способ сделать это - т.е. иметь объект val, инициализированный со значениями, неизвестными до выполнения?

Ответы

Ответ 1

Почему бы не использовать class и не инициализировать один экземпляр в main?

case class Field(width: Int, height: Int) {
  //...
}

object Main {
  def main(args: Array[String]): Unit = {
    val field = Field(30, 25)
  }
}

Ответ 2

Вы можете использовать ленивые деньги. Это может сделать вещи более сложными, если вам все еще нужно использовать var.

case class Config( height: Int, width: Int )
object Field {
  val defaultConfig = Config( 20, 15 )
  var config: Option[Config] = None
  def getConfig = config.getOrElse( defaultConfig )
  lazy val height = getConfig.height
  lazy val width = getConfig.width
}
object Main extends App {
  Field.config = Some( Config( 30, 25 ) )
}

Ответ 3

Один вариант - ленивый vals:

object Field {
  lazy val height = // code to find height
  lazy val width = // code to find width
}

Значение val будет инициализировано при первом использовании, поэтому пока вы не будете использовать их, пока не получите всю информацию, необходимую для их инициализации, вы должны быть хорошими.