Программирование с ИИ
ENRU
11.2

Dart за полчаса

что надо знать, чтобы читать

Что это

Dart похож одновременно на Java, JavaScript и TypeScript. Если ты прочитал главу 9, половина уже знакома: типы, async/await, классы.

В статье — то, что отличается и встречается в каждом файле Flutter-проекта.

Как выглядит в коде

class City {
  final String name;
  final double? temp;

  const City({required this.name, this.temp});

  String get report => temp == null
      ? '$name: нет данных'
      : '$name: ${temp! > 0 ? '+' : ''}$temp°';
}

void main() {
  final cities = <City>[
    const City(name: 'Oslo', temp: 4),
    const City(name: 'Tromsø'),
  ];

  for (final c in cities) {
    print(c.report);
  }
}

Что здесь важно

final вместо const и let. final — присвоить один раз. const — значение известно на этапе компиляции. Во Flutter const встречается постоянно: он позволяет не пересоздавать виджеты при перерисовке.

double? temp — тип с вопросом, то же, что number | null в TypeScript. Dart строг к пустоте так же, как TypeScript со strict: обратиться к temp напрямую нельзя, пока не проверил.

temp! — утверждение «тут точно не пусто». Прямой аналог as из статьи 9.5 и такой же источник проблем: это обещание компилятору, а не проверка. Если ошибся, приложение упадёт с Null check operator used on a null value.

required — обязательный именованный параметр. Без него аргумент можно не передать.

$name и ${выражение} — подстановка в строку, как f-строки в Python.

get report => ... — вычисляемое свойство: обращаются как к полю, без скобок.

Именованные параметры

Главное синтаксическое отличие, к которому надо привыкнуть:

City(name: 'Oslo', temp: 4)          // именованные, в фигурных скобках

Во Flutter почти все параметры именованные, и это объясняет, почему код выглядит таким многословным:

Padding(
  padding: const EdgeInsets.all(16),
  child: Text('Привет'),
)

Плюс в том, что при чтении всегда видно, что означает каждое значение.

Остальное коротко

ЗаписьЧто значит
late«значение будет, но позже» — обещание, проверяется при работе
?.безопасный доступ, как в JS (статья 9.1)
??значение по умолчанию
..каскад: несколько операций с одним объектом
=>короткая форма функции из одного выражения
List<City>список городов; <> — как дженерики (статья 9.4)

late стоит упомянуть отдельно. Это способ сказать «я присвою это позже». Если не присвоил, а обратился — ошибка во время работы. ИИ использует late, чтобы обойти требование инициализации, — и это та же заглушка, что as и !.

Как сказать ИИ

Запрос
Объясни этот класс построчно: что значит final, что
required, что делает знак восклицания после temp.
Запрос
Здесь используется `late` и `!`. Перепиши без них,
через нормальные проверки на null. Если где-то без них
не обойтись — объясни почему, а не переписывай.
Запрос
Напиши модель данных для ответа API: вот пример JSON.
Поля, которых может не быть, делай nullable честно.
Добавь фабрику fromJson с проверками, а не приведением типов.

На что смотреть

! на каждом шагу. Приложение будет падать там, где данных не оказалось.

late вместо нормальной инициализации. Та же проблема, только позже.

Код для старых версий Flutter. Устаревшие имена виджетов и параметров.

dynamic. Полный аналог any из TypeScript: отключает проверку.

Разбор JSON без проверок. json['main']['temp'] as double падает, если сервер ответил ошибкой, — ровно так же, как в статьях 2.12 и 9.5.

Шпаргалка

  • final — присвоить один раз, const — известно при компиляции.

  • double? — может быть пустым; Dart не даст обратиться без проверки.

  • !, late и приведение типа отключают проверку пустоты.

  • Параметры во Flutter почти всегда именованные: City(name: ..., temp: ...).

  • $name и ${выражение} — подстановка в строку.

  • dynamic — это any, со всеми последствиями.