Переменные Late
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 19 из 110.
Ключевое слово late сообщает Dart, что не допускающая значения null переменная будет инициализирована перед использованием, даже если она не присвоена сразу. Это полезно, когда вы не можете инициализировать поле при объявлении или в конструкторе, но уверены, что оно будет иметь значение перед обращением к нему.
class User {
late String username;
void initialize(String name) {
username = name;
}
void greet() {
print('Hello, $username!');
}
}
User user = User();
user.initialize('Alice');
user.greet(); // Привет, Alice!Без late Dart выдал бы ошибку, что username не инициализирована. Модификатор late обещает, что вы присвоите значение перед его чтением.
Еще одним преимуществом late является ленивая инициализация. Переменная late с инициализатором не будет вычислять свое значение до первого обращения:
class Config {
late String settings = loadSettings();
String loadSettings() {
print('Loading...');
return 'default';
}
}
Config config = Config();
print('Config created');
print(config.settings); // "Loading..." выводится здесь, затем "default"Метод loadSettings() выполняется только при первом обращении к settings, а не при создании объекта. Однако будьте осторожны — обращение к переменной late до её инициализации вызывает ошибку времени выполнения.
Задание
ЛегкоДавайте создадим менеджер подключения к базе данных, который демонстрирует как отложенную инициализацию, так и ленивую инициализацию с использованием переменных late.
Вы создадите два файла для организации вашего кода:
database.dart: Определите классDatabase, который имитирует подключение к базе данных. Ваш класс должен иметь:- Переменную
late String connectionString, которая будет установлена после создания объекта - Переменную
late String statusс ленивым инициализатором, который выводитChecking connection...и возвращает'Connected' - Метод
connect(String connStr), который устанавливаетconnectionStringи выводитConnection configured: [connectionString] - Метод
query(String sql), который выводитExecuting on [connectionString]: [sql] - Метод
checkStatus(), который выводитStatus: [status](это вызовет ленивую инициализацию при первом вызове)
- Переменную
main.dart: Импортируйте ваш класс базы данных и продемонстрируйте оба варианта использованияlate:- Создайте экземпляр
Database - Выведите
Database object created - Вызовите
connect()со строкой подключения'localhost:5432/mydb' - Вызовите
query()с'SELECT * FROM users' - Вызовите
checkStatus(), чтобы запустить ленивую инициализацию
- Создайте экземпляр
Обратите внимание, как connectionString устанавливается вручную после создания объекта, в то время как status вычисляет свое значение только при первом доступе.
Ожидаемый вывод:
Database object created
Connection configured: localhost:5432/mydb
Executing on localhost:5432/mydb: SELECT * FROM users
Checking connection...
Status: ConnectedШпаргалка
Ключевое слово late позволяет объявлять переменные, не допускающие значения null (non-nullable), которые будут инициализированы позже, перед их использованием:
class User {
late String username;
void initialize(String name) {
username = name;
}
}
User user = User();
user.initialize('Alice');Ленивая инициализация: Переменная с модификатором late, имеющая инициализатор, вычисляет своё значение только при первом обращении:
class Config {
late String settings = loadSettings();
String loadSettings() {
print('Loading...');
return 'default';
}
}
Config config = Config(); // loadSettings() еще не вызвана
print(config.settings); // loadSettings() вызывается здесьВнимание: Обращение к переменной late до её инициализации вызывает ошибку во время выполнения (runtime error).
Попробуйте сами
import 'database.dart';
void main() {
// TODO: Создать экземпляр Database
// TODO: Вывести 'Database object created'
// TODO: Вызвать connect() с 'localhost:5432/mydb'
// TODO: Вызвать query() с 'SELECT * FROM users'
// TODO: Вызвать checkStatus() для запуска ленивой инициализации
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
1Основы ООП
Внешние файлыБиблиотеки и импортВведение в ООПКлассы и объектыКлючевое слово thisМетодыПеременные экземпляраОсновы конструкторовИтоги — Простой калькулятор4Null-безопасность
Введение в Null-безопасностьNullable и Non-Nullable типыОператоры ? и !Ключевое слово Late и Null-безопасностьNull-aware операторыNull-безопасность в классахИтоги — Система профилей пользователей7Абстрактные классы и интерфейсы
Абстрактные классыАбстрактные методыИнтерфейсы в DartНеявные интерфейсыРеализация против наследованияМножественные интерфейсыИтоги — Калькулятор фигур10Коллекции и обобщения
Обзор List, Set, MapТипобезопасные коллекцииОбобщенные классыОбобщенные методыОграничения обобщенийIterable и IteratorИтоги: Обобщенное хранилище13Продвинутые концепции ООП
Композиция против наследованияМетоды расширенияВызываемые классыЗапечатанные классы (Dart 3)Записи (Dart 3)Паттерны и сопоставление (3.0)Перечисления с методами16Проект: Управление библиотекой
Обзор проектаКлассы Book и User2Конструкторы в Dart
Конструктор по умолчаниюИменованные конструкторыСписки инициализацииКонстантные конструкторыФабричные конструкторыПеренаправляющие конструкторыИтоги — Shape Builder5Инкапсуляция
Публичные и приватные членыСоглашение о префиксе _Приватность на уровне библиотекГеттеры и сеттеры: подробный разборСкрытие данныхИтоги — Записи о студентах8Mixins
Введение в MixinsСоздание MixinsИспользование нескольких MixinsКлючевое слово on в MixinsMixin и наследованиеMixin и интерфейсИтоги: Система животных11Специальные методы
Переопределение toString()Переопределение hashCode и ==Интерфейс ComparableМетод call()Переопределение noSuchMethodПовторение — Пользовательская коллекция14Паттерны проектирования. Часть 1
Введение в паттерны проектированияПаттерн SingletonПаттерн FactoryПаттерн ObserverПаттерн Strategy3Свойства классов
Члены экземпляра и статические членыПоля Final и ConstПеременные LateСтатические методы и поляГеттеры и сеттерыИтоги — Менеджер банковского счета6Наследование
Основы наследованияКлючевое слово superПереопределение методовАннотация @overrideКлючевое слово final для классовКонструкторы и наследованиеИтоги: Иерархия сотрудников9Полиморфизм
Основы полиморфизмаПолиморфизм через интерфейсыПроверка типов во время выполненияОператоры is и asКлючевое слово covariantИтоги — Обработчик платежей12Асинхронное ООП
Futures и async/awaitОсновы StreamsКонтроллеры StreamАсинхронные конструкторыАсинхронность в методах классовИтоги — Data Fetcher15Паттерны проектирования. Часть 2
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий