Почему я не могу назначить var в подкласс Scala?

Предположим, что у меня есть следующий абстрактный класс:

abstract class A (var is_happy : Boolean) {
  def toggle_happiness();
}

И теперь я хочу определить конкретный класс, который реализует метод toggle_happiness():

class B (is_happy : Boolean) extends A (is_happy) {
  def toggle_happiness() = {
    is_happy = !is_happy
  }
}

Scala компилятор дает мне:

error: reassignment to val
   is_happy = !is_happy
            ^

Что здесь происходит? Я думал, что is_happy ссылается на var в моем классе, который задается моим конструктором. У меня конфликт с именем is_happy?

Спасибо, Dan

Ответы

Ответ 1

См. этот вопрос. По сути, Scala считает, что вы пытаетесь назначить параметр конструктора is_happy, а не var, is_happy, который, как раз, имеет одно и то же имя. Некоторые решения заключаются в следующем:

  • Сделайте реферат var в базовом классе.
  • Переименуйте параметр конструктора (например, _is_happy). Поскольку имена параметров являются частью общедоступного API ваших конструкторов/методов, это может нецелесообразно.

Вам повезло, что проблема была обнаружена во время компиляции в вашем случае. Эта проблема может привести к очень удивительному поведению во время выполнения, когда оно не обнаружено.

Ответ 2

Существует еще одно простое решение. Тот, который требует только изменить B (не нужно менять базовый класс) и не будет изменять интерфейс (без переименования параметров). Просто введите частный метод, который возвращает это, и явно разыщите это:

class B (var is_happy : Boolean) extends A {
  private def self = this
  def toggle_happiness() = {
    self.is_happy = !self.is_happy
  }
}

Обратите внимание, что эта работа локализована в B. Всюду (включая производные классы) вы можете использовать только is_happy (нет необходимости в self.is_happy).


В качестве побочного примечания мы должны действительно иметь возможность прямого разыменования this, как в this.is_happy (вместо добавления метода self и выполнения self.is_happy). Но по какой-то причине компилятор будет слепо трактовать this.is_happy так же, как is_happy, поэтому мы вернемся к квадрату, а this.is_happy на самом деле все еще укажем на параметр B, а не на переменную A. Это очень похоже на ошибку компилятора.