Подтвердить что ты не робот

Scala переопределение не-абстрактного def с var

В Scala я могу сделать это:

trait SomeTrait {
  protected def foo: String
}

class Wibble extends SomeTrait {
  protected var foo = "Hello"
}

Но я не могу сделать то же самое, где я предоставляю определение по умолчанию для foo

trait SomeTrait {
  protected def foo: String = "World"
}

class Wibble extends SomeTrait {
  protected var foo = "Hello" //complains about lack of override modifier

  override protected var foo = "Hello" //complains "method foo_ overrides nothing"
}

Почему я не могу это сделать?

EDIT: после разговора в списке рассылки scala -users у меня поднял это в trac

4b9b3361

Ответ 1

В Scala, когда вы пишете var foo, компилятор Scala автоматически генерирует сеттер (называемый foo_=) и getter (называемый foo) для него и устанавливает это поле как личное ( вы увидите его закрытым, если вы декомпилируете класс с "общедоступными" Scala полями с javap). То, что означает "метод foo_ = переопределяет ничего", означает ошибку. В вашей характеристике вы не определили метод foo_=, а для публичного поля setter и getters всегда попадают парами.

Если вы не указали значение по умолчанию в признаке (т.е. абстрактный метод), то ключевое слово override не требуется. Поэтому в вашем первом примере геттер переопределяет абстрактный метод и сеттер... он просто есть. Компилятор не жалуется. Но когда вы предоставляете фактическую реализацию метода в признаке, вам нужно специально написать ключевое слово override при переопределении. При написании protected var foo вы не указали ключевое слово override для получателя, а при записи override protected var foo вы также указали компилятору, что метод foo_= должен быть переопределен, но этот признак не имеет такого метода.

Кроме того, логически вы не можете переопределить def с помощью var (учитывая строгий обзор переопределения, как в предыдущем абзаце). A def логически является функцией (вы даете ей некоторый ввод, она производит вывод). A var похож на функцию no-arg, но также поддерживает установку его значения на что-то еще, операцию, которая не поддерживается функцией. Вместо этого, если вы измените его на val, все будет в порядке. Он похож на функцию, которая всегда производит тот же (кешированный) результат.

Если вы хотите иметь подобное поведение с var, вы можете сделать что-то вроде этого (с помощью явного setter и getters):

class Wibble extends SomeTrait {
  private var bar = "Hello"
  override protected def foo = bar
  protected def foo_=(v: String) { bar = v}
}

Теперь вы можете делать все, что вы можете сделать с var:).

val x = new Wibble
println(x.foo) // yields "Hello"
x.foo = "Hello again"
println(x.foo) // yields "Hello again"