Declaring и Primary Constructors в Dart

Я — MADTeacher, автор книг по Dart/Flutter/ИИ в программировании и преподаватель. На канале разбираю свежие фичи языка и фреймворка, объясняю, как и когда их применять, и показываю всё на живых примерах кода. Меньше воды — больше практики: от конструкторов и метапрограммирования до производительности, интеропа и тестирования, а также поднимаю тему использования ИИ для разработки программных продуктов. Если хотите понимать Dart и Flutter в эпоху ИИ глубже — вы по адресу.

Dartprimary constructordeclaring constructor

Основная цель данной фичи – уменьшение количества кода при объявлении класса. Так, например:

🚨 Первичный конструктор значительно упрощает объявление класса, перенося объявления его полей в сам конструктор в заголовок класса:

// сейчас
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. пощупать фичу пока нельзя, т.к. под нее еще не был заведен экспериментальный флаг. Скорей всего он появится только в следующем году🫠

Ждем?

  • 👍 - О, да тетка!!!
  • 👌 - Ну приняли фичу и приняли
  • 👎 - не вижу от этой фичи пользы
Баннер: заголовок «Что же Dart такого нам готовит?» слева и круглый портрет автора Станислава Чернышева справа на темном фоне, превью канала.
Превью поста с заголовком и портретом автора.

Дискуссия

TheLastRay (:
Как думаешь, насколько сложно это реализуется?
MADTeacher | Станислав Чернышев
TheLastRay (:
Как думаешь, насколько сложно это реализуется?
Чего-то сверх-сложного тут нет, по сути эти конструкторы - синтаксический сахар
TheLastRay (:
MADTeacher | Станислав Чернышев
Чего-то сверх-сложного тут нет, по сути эти конструкторы - синтаксический сахар
Ну да, но по твоим примерным срокам грустно выглядит ( хоть и понимаешь, что у них есть и другие задачи
S Afanasov
лучше бы они доработку сделали которая бы позволяля в теле конструктора инициализировать final поля
Александр Медведев
Правильно понял, что мы ОБЯЗАНЫ писать var или final перед полями в случае primary и declaring конструкторов?
Александр Медведев
Спасибо за обзор!
MADTeacher | Станислав Чернышев
Александр Медведев
Правильно понял, что мы ОБЯЗАНЫ писать var или final перед полями в случае primary и declaring конструкторов?
Правильно
TheLastRay (:
S Afanasov
лучше бы они доработку сделали которая бы позволяля в теле конструктора инициализировать final поля
late: 🗿 🗿 🗿
Присоединиться к обсуждению →

Читайте так же