Menu
Coddy logo textTech

Ключевое слово Late и Null-безопасность

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy. Урок 26 из 110.

Иногда вам нужна переменная, допускающая значение null, но вы не можете сразу присвоить ей значение. Ключевое слово late сообщает Dart: «Я обещаю инициализировать её до того, как использовать».

late String description;

void setup() {
  description = 'Initialized later';
}

void main() {
  setup();
  print(description);  // Работает - инициализировано перед использованием
}

Без late Dart пожаловался бы, что description не initialized. С late ты берёшь на себя ответственность за то, чтобы до обращения к нему у него было значение. Если попытаться прочитать его до инициализации, возникнет ошибка во время выполнения.

Распространённый вариант использования — ресурсоёмкие вычисления, которые вы хотите отложить до момента, когда они действительно понадобятся:

class DataProcessor {
  late List<int> data = _loadData();
  
  List<int> _loadData() {
    print('Loading data...');
    return [1, 2, 3, 4, 5];
  }
}

DataProcessor processor = DataProcessor();
// 'Loading data...' ещё не напечаталось
print(processor.data);  // Теперь оно загружается и печатается

Метод _loadData() выполняется только при первом обращении к data, а не при создании объекта. Такая ленивая инициализация может повысить производительность, если значение никогда не понадобится.

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

challenge icon

Задание

Легко

Давайте создадим менеджер конфигурации, демонстрирующий возможности переменных late для отложенной инициализации. Вы создадите систему, в которой ресурсоёмкие операции настройки выполняются только тогда, когда конфигурация действительно необходима.

Вы организуете код в двух файлах:

  • config_manager.dart: объявите класс ConfigManager, который управляет настройками приложения. Класс должен иметь:
    • String appName, передаваемый через constructor
    • late String databaseUrl, который будет инициализирован позже с помощью метода настройки
    • late int maxConnections с ленивой инициализацией, которая при первом обращении выводит Calculating max connections... и возвращает 100
    • метод setupDatabase(String url), который инициализирует databaseUrl
    • метод displayConfig(), который выводит текущую конфигурацию
  • main.dart: импортируйте свой менеджер конфигурации и продемонстрируйте работу переменных late:
    • Создайте ConfigManager с именем приложения 'MyApp'
    • Выведите Config created
    • Вызовите setupDatabase с URL 'localhost:5432/mydb'
    • Выведите Accessing max connections...
    • Выведите значение maxConnections
    • Выведите Accessing max connections again...
    • Снова выведите значение maxConnections (обратите внимание, что сообщение о вычислении не повторяется)
    • Вызовите displayConfig()

Метод displayConfig() должен выводить данные в следующем формате:

--- Configuration ---
App: [appName]
Database: [databaseUrl]
Max Connections: [maxConnections]

Обратите внимание, что вычисление maxConnections с ленивой инициализацией выполняется только один раз — при первом обращении к нему. В этом и заключается преимущество late с инициализатором!

Ожидаемый результат:

Config created
Accessing max connections...
Calculating max connections...
100
Accessing max connections again...
100
--- Configuration ---
App: MyApp
Database: localhost:5432/mydb
Max Connections: 100

Попробуйте сами

import 'config_manager.dart';

void main() {
  // TODO: Создайте ConfigManager с именем приложения 'MyApp'
  
  // TODO: Print 'Config created'
  
  // TODO: Call setupDatabase with URL 'localhost:5432/mydb'
  
  // TODO: Print 'Accessing max connections...'
  
  // TODO: Print the value of maxConnections
  
  // TODO: Print 'Accessing max connections again...'
  
  // TODO: Print the value of maxConnections again
  // (обратите внимание, что сообщение о вычислении не повторяется)
  
  // TODO: Вызовите displayConfig()
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Dart