Введение в Null-безопасность
Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy — урок 23 из 110.
Одной из наиболее распространенных причин ошибок в программировании является попытка использовать значение, которое не существует. В Dart это специальное «отсутствие значения» представлено как null. Функция null safety в Dart помогает обнаруживать эти ошибки еще до запуска вашего кода.
Без null safety любая переменная потенциально может быть null, что приводит к сбоям во время выполнения при попытке её использования:
// В старых версиях Dart (без null safety)
String name; // Может быть null!
print(name.length); // Сбой, если name равно nullПри включенной проверке на null (null safety) (Dart 2.12+), компилятор различает переменные, которые могут содержать null, и те, которые не могут. По умолчанию переменные являются не допускающими значение null (non-nullable) — они всегда должны содержать допустимое значение:
String name = 'Alice'; // Должна иметь значение
print(name.length); // Безопасно — name никогда не равно nullКомпилятор откажется компилировать код, в котором переменная, не допускающая значения null (non-nullable), может иметь значение null. Это переносит обнаружение ошибок со стадии выполнения на стадию компиляции, делая ваши программы более надежными. В следующих уроках вы узнаете, как объявлять типы, допускающие значение null (nullable), когда они вам действительно необходимы, и познакомитесь с операторами, которые предоставляет Dart для безопасной работы с потенциально нулевыми значениями.
Задание
ЛегкоДавайте создадим простую систему контактных карточек, которая демонстрирует важность не допускающих значения null переменных. Вы создадите систему, в которой каждый контакт должен иметь корректную, гарантированную информацию.
Вы организуете свой код в двух файлах:
contact.dart: Определите классContact, который представляет контактную информацию человека. Поскольку мы работаем с null safety, каждое поле должно иметь корректное значение — отсутствие данных не допускается! Ваш класс должен содержать:String firstNameдля имени контактаString lastNameдля фамилии контактаString emailдля адреса электронной почты контактаint phoneDigitsдля количества цифр в номере телефона- Конструктор, принимающий все четыре значения
- Геттер
fullName, который возвращает имя и фамилию, объединенные пробелом - Метод
displayCard(), который выводит информацию о контакте
main.dart: Импортируйте ваш класс контакта и создайте два контакта, чтобы продемонстрировать, что все поля гарантированно имеют значения:- Создайте контакт с именем
'Emma', фамилией'Wilson', электронной почтой'emma@mail.com'и количеством цифр в телефоне10 - Создайте контакт с именем
'James', фамилией'Brown', электронной почтой'james@work.com'и количеством цифр в телефоне11 - Вызовите
displayCard()для каждого контакта в указанном выше порядке
- Создайте контакт с именем
Метод displayCard() должен выводить данные именно в таком формате:
--- Contact Card ---
Name: [fullName]
Email: [email]
Phone digits: [phoneDigits]Обратите внимание, что каждая переменная должна быть инициализирована реальным значением — это null safety в действии! Компилятор гарантирует, что при доступе к fullName, email или любому другому полю они всегда будут содержать корректные данные.
Ожидаемый вывод:
--- Contact Card ---
Name: Emma Wilson
Email: emma@mail.com
Phone digits: 10
--- Contact Card ---
Name: James Brown
Email: james@work.com
Phone digits: 11Шпаргалка
Dart использует безопасность null (null safety) для предотвращения ошибок, вызванных использованием несуществующих значений. Специальное значение null представляет отсутствие значения.
При включенной безопасности null (Dart 2.12+), переменные по умолчанию являются не допускающими значение null (non-nullable) — они всегда должны содержать корректное значение:
String name = 'Alice'; // Должна иметь значение
print(name.length); // Безопасно — name никогда не равно nullКомпилятор предотвращает компиляцию кода, если переменная, не допускающая значение null, может оказаться null, перенося обнаружение ошибок со времени выполнения на этап компиляции.
Попробуйте сами
import 'contact.dart';
void main() {
// TODO: Создайте первый контакт со следующими данными:
// - имя: 'Emma'
// - фамилия: 'Wilson'
// - email: 'emma@mail.com'
// - количество цифр в номере: 10
// TODO: Создайте второй контакт со следующими данными:
// - имя: 'James'
// - фамилия: 'Brown'
// - email: 'james@work.com'
// - количество цифр в номере: 11
// TODO: Вызовите displayCard() для каждого контакта по порядку
}
В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.
Все уроки раздела Объектно-ориентированное программирование
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
Паттерн КомандаПаттерн АдаптерПаттерн ДекораторПаттерн Шаблонный методПаттерн СостояниеПаттерн КомпоновщикПаттерн Репозиторий