Конструкторы в 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
}
Ясно, что это уступает определению полей в основном конструкторе, который является той точкой, которую я хотел бы сделать.