Как создать подкласс для объекта с переменной var в его первичном конструкторе - PullRequest
7 голосов
/ 17 ноября 2009

Я хочу сделать что-то вроде этого:

class A (var updateCount: Int) {
}

class B (val name: String, var updateCount: Int) extends A(updateCount) {
  def inc(): Unit = {
    updateCount = updateCount + 1
  }
}

var b = new B("a", 10)
println(b.name)
println(b.updateCount)

b.updateCount = 9999
b.inc
println(b.updateCount)

но компилятору это не нравится.

(fragment of extend.scala):5: error: error overriding variable updateCount in class A of type Int;
 variable updateCount needs `override' modifier
class B (val name: String, var updateCount: Int) extends A(updateCount) {

Добавление переопределения на updateCount также не работает. Какой чистый способ сделать это?

Ответы [ 4 ]

7 голосов
/ 17 ноября 2009

Вам не нужно объявлять var в сигнатуре конструктора подкласса:

class B (val name: String, /* note no var */ updateCount: Int) extends A(updateCount) {
  //...
}

Это также распространяется на классы с val s в их конструкторах:

scala> class C(val i: Int)
defined class C

scala> class D(j: Int) extends C(j)
defined class D
4 голосов
/ 17 ноября 2009

Вы должны избегать объявления идентификатора для B, скрывающего идентификатор, объявленный для A. Самый простой способ сделать это - выбрать другое имя. Однако если вы действительно не хотите этого делать, вот альтернатива:

class B (val name: String, updateCount: Int) extends A(updateCount) {
  self: A =>
  def inc(): Unit = {
    self.updateCount = self.updateCount + 1
  }
}

И, кстати, отбросить объявление var из B.

2 голосов
/ 17 ноября 2009

Когда вы используете ключевое слово var в параметрах, это делает переданное значение новым var в классе. Когда вы этого не делаете, это делает его параметром конструктора (только), и вы используете его значение для var, передавая его конструктору. Итак, пример, который люди привели

class B(val name:String, updateCount:Int) extends A(updateCount)

правильно.

Однако scala делает параметры конструктора непосредственно доступными для методов в классе (я не уверен почему), поэтому, если вы используете то же имя, вы обнаружите, что ваш код не может скомпилироваться с ошибкой reassignment to val, когда попробуйте переназначить "var". Например, в следующем фрагменте неизменяемый параметр конструктора затеняет унаследованный var, поэтому вы не можете назначить этому параметру.

class B (val name: String, updateCount: Int) extends A(updateCount) {
  def inc(): Unit = {
    updateCount = updateCount + 1
  }
}
0 голосов
/ 23 ноября 2009

Как уже упоминалось, ваш параметр конструктора в B скрывает версию суперкласса. Вот код, который работает и не требует самостоятельного ввода:

class A (var updateCount: Int) {
}

class B (val name: String, uc: Int) extends A(uc) {
  def inc(): Unit = {
    updateCount = updateCount + 1
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...