Могу ли я определить «закрытые для метода» поля в Scala? - PullRequest
3 голосов
/ 09 декабря 2010

Учитывая эту ситуацию:

object ResourceManager {

  private var inited = false

  def init(config: Config) {
    if (inited)
      throw new IllegalStateException
    // do initialization
    inited = true
  }

}

Есть ли способ, которым я мог бы сделать inited каким-то образом «закрытым для init ()», так что я могу быть уверен, что никакой другой метод в этом классе никогда не сможет установить inited = false?

Ответы [ 4 ]

6 голосов
/ 09 декабря 2010

Взято из Как в Scala вы объявляете статические данные внутри функции? .Не используйте метод, но объект функции:

val init = { // or lazy val
  var inited = false

  (config: Config) => {
      if (inited)
          throw new IllegalStateException

      inited = true
  }
}

Во время инициализации внешней области (в случае val) или первого доступа (lazy val) выполняется тело переменной,Таким образом, inited устанавливается на false.Последнее выражение является анонимной функцией, которая затем присваивается init.Каждый последующий доступ к init будет затем выполнять эту анонимную функцию.

Обратите внимание, что она не ведет себя точно как метод.Т.е. совершенно правильно называть это без аргументов.Затем он будет вести себя как метод с последующим подчеркиванием method _, что означает, что он просто вернет анонимную функцию без жалоб.

Если по той или иной причине вам действительно нужно поведение метода, вы можете сделать этоprivate val _init = ... и позвоните по телефону def init(config: Config) = _init(config).

5 голосов
/ 09 декабря 2010

Нижеследующее абсолютно считается более серьезной проблемой, но оно удовлетворяет спецификациям.Там нет никакого способа сделать это иначе

object ResourceManager {

  private object foo {
     var inited = false
     def doInit(config:Config){
       if (inited)
         throw new IllegalStateException
       // do initialization
       inited = true
     }
  }


  def inner(config: Config) {
      foo.doInit(config)
  }

}
0 голосов
/ 09 декабря 2010

Если все, что вы хотите сделать, это убедиться, что init вызывается один раз, сделайте что-то вроде этого:

lazy val inited = {
  // do the initialization
  true
}

def init = inited

таким образом код инициализации будет запускаться только один раз, однако сколько раз вы запускаете init, и inited не может получить другое значение, так как это val. Единственным недостатком является то, что, как только inited запрашивается его значение, инициализация будет выполняться ...

0 голосов
/ 09 декабря 2010

Было бы проще создать объект "люка", который может переходить только от ложного к истинному:

object ResourceManager {

  object inited {
    private var done = false

    def apply() = done
    def set = done = true
  }

  def init(config: Int) {

    if (inited())
      throw new IllegalStateException
    // do initialization
    inited.set
  }

}
...