Основная цель данной фичи – уменьшение количества кода при объявлении класса. Так, например:
🚨 Первичный конструктор значительно упрощает объявление класса, перенося объявления его полей в сам конструктор в заголовок класса:
// сейчас
class Point {
int x;
int y;
Point(this.x, this.y);
}
// primary constructor
class Point(var int x, var int y);
В зависимости от того, должно ли значение поля изменяться в процессе жизни экземпляра класса или нет – перед указанием его типа ставится var или final. Если они опускаются, то поле должно быть явно объявлено в теле класса.
И казалось бы – крутота! И на кой понадобился еще один тип конструктора – declaring constructor? Все дело в том, что у первичного конструктора есть ряд ограничений:
- 👉 класс, объявленный посредством первичного конструктора, не может иметь других генеративных конструкторов без перенаправления на базовый (первичный) конструктор. Это требование должно соблюдаться для обеспечения гарантии того, что первичный конструктор действительно выполняется при создании каждого нового экземпляра этого класса.
class Point(var int x, var int y) {
// ✔️ redirecting
Point.origin() : this(0, 0);
// ✔️ factory
factory Point.unit() => Point(1, 1);
// ❌ нельзя
// Point.bad() { x = 0; y = 0; }
}
- 👉 при использовании первичного конструктора нет возможности явно задать тело конструктора. По факту, телом конструктора при таком объявлении класса будет считаться само тело класса
- 👉 нельзя задавать списки инициализации. Но есть способ обхода этого ограничения (как и с телом конструктора - перенести операции из списка инициализации в тело класса):
// сейчас
class DeltaPoint {
final int x;
final int y;
DeltaPoint(this.x, int delta): y = x + delta;
}
// primary constructor.
class DeltaPoint(final int x, int delta) {
final int y = x + delta;
}
🚨 Declaring Constructor объявляется через ключевое слово this и вбирает в себя все плюшки первичного, добавляя большей гибкости при инициализации экземпляра класса, а именно:
🤌 Конструктор класса (обычный / константный / именованный) может содержать тело и список инициализации, либо быть объявлен без него:
class Point {
this(var int x, var int y); // без тела
}
class Point { // без тела но со списком инициализации
this(var int x, var int y): assert(0 <= x && x <= y * y);
}
class Point {
this(var int x, var int y){ // тело конструктора }
}
class Point {
// приватный конструктор по умолчанию
const this._(final int x, final int y);
}
🤌 Нет ограничений на количество объявляемых таким образом конструкторов
⁉️ Так когда какой конструктор использовать?
Просто data‑класс? → primary Много параметров? → declaring Нужен еще один конструктор? → declaring / по старинке Имеется late / external / сложная логика? → по старинке / declaring + отдельное поле, объявленное в теле класса
По большому счету, теперь что первый, что второй тип конструктора упоминается, как declaring, с тем отличием, что декларативный конструктор, указываемый в заголовке класса принято называть – первичным.
p.s. пощупать фичу пока нельзя, т.к. под нее еще не был заведен экспериментальный флаг. Скорей всего он появится только в следующем году🫠
Ждем?
- 👍 - О, да тетка!!!
- 👌 - Ну приняли фичу и приняли
- 👎 - не вижу от этой фичи пользы


Дискуссия