Что такое ‘late’ инициализация (late init) в Dart?

«Что такое ‘late’ инициализация (late init) в Dart?» — вопрос из категории Dart Core, который задают на 29% собеседований Flutter Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

В Dart не существует отдельной конструкции late init. Под этим обычно понимается использование модификатора late для реализации отложенной (deferred) или ленивой (lazy) инициализации non-nullable полей.

Два основных паттерна "late init":

1. Отложенная инициализация (Deferred Initialization) Значение присваивается явно где-то в коде (в конструкторе, в initState, в методе) до первого чтения.

class ProfileBloc {
  late final ProfileRepository _repo; // Объявляем как late
  late final StreamController _controller;

  ProfileBloc() {
    // Инициализируем в конструкторе, но не в списке инициализаторов
    _repo = ProfileRepository();
    _controller = StreamController.broadcast();
  }

  void dispose() {
    _controller.close(); // Гарантированно инициализировано
  }
}

2. Ленивая инициализация (Lazy Initialization) Значение вычисляется и присваивается только в момент первого обращения к полю (getter). Инициализатор выполняется один раз.

class AppSettings {
  // _settingsCache будет вычислен только при первом вызове `settings`
  late final Map<String, dynamic> _settingsCache = _loadSettingsFromDisk();

  Map<String, dynamic> _loadSettingsFromDisk() {
    print('Loading settings...'); // Выведется только один раз
    // Тяжелая операция чтения файла
    return {'theme': 'dark', 'language': 'en'};
  }

  String get theme => _settingsCache['theme']; // Здесь произойдет инициализация
}

Сравнение с альтернативами:

  • late vs ? (nullable): late требует гарантированной инициализации и выбрасывает четкую ошибку при её нарушении. String? требует постоянных проверок на null.
  • late final: Комбинация late с final означает, что после инициализации значение поля изменить нельзя.

Итог: late — это инструмент для работы со строгой null-безопасностью Dart, позволяющий отложить инициализацию, сохраняя гарантии non-nullable типов.