Конструкторы в scala (первичный/вспомогательный/основной по умолчанию)

Простейшее упражнение из книги Кей Хорстмана "Scala для нетерпеливого" меня озадачивает. Это о конструкторах primary, auxiliary и default primary:

ex 5.10:Рассмотрим класс

class Employee(val name: String, var salary: Double) {
  def this() { this("John Q. Public", 0.0) }
}

Перепишите его для использования явных полей и основного конструктора по умолчанию.

Я не уверен, что я должен это делать. Может ли кто-нибудь из вас предложить решение?

Однако попытка решить это упражнение, возможно, заставило меня узнать о чем-то, чего я раньше не замечал об основных конструкторах и val (как вы можете видеть, я не совсем уверен):

Правильно ли, если я скажу, что поле val (как name в классе Employee выше) может быть инициализировано только с помощью конструктора primary, а не с помощью auxiliary one? В последнем случае компилятор будет рассматривать как переназначение в поле val, вызывающее ошибку.

Сначала я думал, что поля val являются грубым эквивалентом конечным полям java, ожидающим, что было бы законно назначать их в первый раз в любом конструкторе, но, похоже, я ошибался.

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

Ответ 1

От "Программирование в Scala, 2-е издание", пункт 6.7:

В Scala каждый вспомогательный конструктор должен вызывать другой конструктор того же класса, что и его первое действие. Чистый эффект этого правила заключается в том, что каждый вызов конструктора в Scala в конечном итоге вызовет первичный конструктор класса. Таким образом, основной конструктор является единственной точкой входа класса.

Таким образом, все данные для инициализации val должны быть в основном конструкторе.

Ваш класс с явными полями может выглядеть примерно так:

class Employee(n: String = "John Q. Public", s: Double = 0.0) {
  val name = n
  var salary = s
}

или без значений параметров по умолчанию:

class Employee(n: String, s: Double) {
  def this() = this("John Q. Public", 0.0)
  val name = n
  var salary = s
}

Ответ 2

Собственно, я имел в виду версию с основным конструктором без аргументов, например:

class Employee {
  private var _name = "John Q. Public"
  var salary = 0.0
  def this(n: String, s: Double) { this(); _name = n; salary = s; }
  def name = _name      
}

Ясно, что это уступает определению полей в основном конструкторе, который является той точкой, которую я хотел бы сделать.