Каким ключевым словом обозначаются параметры конструктора в data class Kotlin, если они используются только в init блоке
Что проверяют
Это вопрос с подвохом на знание ограничений data class. В обычном классе параметр, нужный только в init, пишут вообще без ключевого слова, а в data class так нельзя. Интервьюер ждёт, заметите ли вы это, и следом спрашивает, как быть, если такой параметр всё-таки нужен.
Как отвечать
Сначала разведите два случая:
- обычный класс: параметр без
valиvarвиден только в блокахinitи в инициализаторах свойств, полем он не становится. Это и есть ответ «никаким ключевым словом»; data class: основной конструктор обязан иметь хотя бы один параметр, и все его параметры должны быть свойствами, то есть сvalилиvar. Голый параметр не скомпилируется.
Причина в генерации кода: equals(), hashCode(), toString(), copy() и componentN() строятся по свойствам основного конструктора. Параметр, который нигде не хранится, copy() воспроизвести бы не смог.
Если значение нужно только для инициализации, варианты такие:
- объявить
valи принять, что поле участвует в сравнении и попадает вtoString(), а оттуда, например, токен легко утекает в логи; - вынести подготовку в фабрику: функция в
companion objectпринимает сырые данные и вызывает конструктор уже с готовыми значениями; - хранить производные значения в свойствах, объявленных в теле класса: в
equals()иcopy()они не входят; - отказаться от
data class, если объекту не нужна семантика значения.
На Android это всплывает в моделях UI-состояния: лишнее свойство, которое отличается у одинаковых по смыслу объектов, ломает сравнение. StateFlow не отфильтрует повтор, а DiffUtil перерисует элемент списка без нужды.
Где спотыкаются
Отвечают «val или var» и не объясняют, почему без них нельзя. Интервьюер ждал именно ограничения data class и связи с генерируемыми методами.
Считают, что private val исключает свойство из equals() и toString(). Видимость на это не влияет: свойство из основного конструктора участвует в сгенерированных методах всё равно.
Не видят разницы между параметром и свойством в обычном классе. Параметр без val недоступен в методах класса, обращение к нему из функции даёт ошибку компиляции.