Menu
Coddy logo textTech

Операторы ? и !

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

При работе с типами, допускающими значение null, Dart предоставляет два основных оператора для безопасного доступа к значениям. Оператор обращения, учитывающий null ?. и оператор утверждения null ! дают вам контроль над тем, как вы обрабатываете потенциально пустые значения.

Оператор ?. безопасно обращается к свойствам или методам nullable-значения. Если значение равно null, все выражение возвращает null вместо того, чтобы вызвать ошибку:

String? name = 'Alice';
print(name?.length);  // 5

name = null;
print(name?.length);  // null (без ошибок!)

Оператор ! сообщает Dart: «Я уверен, что это значение не равно null». Он преобразует тип, допускающий значение null, в тип, не допускающий его, но выдает ошибку, если значение на самом деле равно null:

String? maybeName = 'Bob';
String definite = maybeName!;  // OK - мы утверждаем, что значение не равно null
print(definite.length);  // 3

String? empty = null;
// String crash = empty!;  // Ошибка времени выполнения! Значение было null

Используйте ?., когда вы хотите корректно обрабатывать значения null. Используйте ! только тогда, когда вы абсолютно уверены, что значение существует — возможно, после проверки его с помощью оператора if или когда вы знаете, что логика гарантирует наличие значения. Чрезмерное использование ! сводит на нет цель безопасности null и может привести к сбоям во время выполнения.

challenge icon

Задание

Легко

Давайте создадим систему инвентаризации товаров, которая демонстрирует, как безопасно работать с nullable-значениями, используя операторы ?. и !.

Вы создадите два файла для организации вашего кода:

  • product.dart: Определите класс Product, который представляет товар в инвентаре. Некоторые товары имеют полную информацию, в то время как другие все еще находятся в процессе каталогизации. Ваш класс должен иметь:
    • Non-nullable String name — у каждого товара должно быть название
    • Non-nullable double price — у каждого товара должна быть цена
    • Nullable String? description — у некоторых товаров пока нет описания
    • Nullable String? category — некоторые товары еще не распределены по категориям
    • Конструктор, который принимает name и price как обязательные параметры
    • Метод getDescriptionLength(), который возвращает длину описания, используя ?., или null, если описание отсутствует
    • Метод getCategoryUppercase(), который возвращает категорию в верхнем регистре, используя ! — этот метод предполагает, что категория была установлена
    • Метод displayProduct(), который выводит информацию о товаре, показывая "No description", когда описание равно null, и "Uncategorized", когда категория равна null
  • main.dart: Импортируйте ваш класс продукта и продемонстрируйте работу обоих операторов:
    • Создайте товар с названием 'Laptop' и ценой 999.99, затем установите его описание как 'High-performance computing device' и категорию как 'Electronics'
    • Создайте товар с названием 'Mystery Item' и ценой 49.99 (оставьте описание и категорию как null)
    • Для Laptop: вызовите displayProduct(), выведите 'Description length: [length]', используя getDescriptionLength(), и выведите 'Category: [uppercase]', используя getCategoryUppercase()
    • Для Mystery Item: вызовите displayProduct() и выведите 'Description length: [length]', используя getDescriptionLength() (это выведет null)

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

Product: [name] - $[price]
Description: [description or "No description"]
Category: [category or "Uncategorized"]

Ожидаемый вывод:

Product: Laptop - $999.99
Description: High-performance computing device
Category: Electronics
Description length: 32
Category: ELECTRONICS
Product: Mystery Item - $49.99
Description: No description
Category: Uncategorized
Description length: null

Шпаргалка

Оператор обращения с проверкой на null ?. позволяет безопасно обращаться к свойствам или методам nullable-значений. Если значение равно null, он возвращает null вместо того, чтобы вызывать ошибку:

String? name = 'Alice';
print(name?.length);  // 5

name = null;
print(name?.length);  // null (без сбоя!)

Оператор утверждения о ненулевом значении ! преобразует nullable-тип в non-nullable. Используйте его только тогда, когда вы уверены, что значение не равно null, так как он вызовет ошибку времени выполнения, если значение на самом деле окажется null:

String? maybeName = 'Bob';
String definite = maybeName!;  // OK — утверждает, что значение не null
print(definite.length);  // 3

String? empty = null;
// String crash = empty!;  // Ошибка времени выполнения!

Используйте ?. для корректной обработки null и ! только тогда, когда вы абсолютно уверены в существовании значения.

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

import 'product.dart';

void main() {
  // TODO: Создать продукт с названием 'Laptop' и ценой 999.99
  // Затем установить описание 'High-performance computing device'
  // И установить категорию 'Electronics'
  
  // TODO: Создать продукт с названием 'Mystery Item' и ценой 49.99
  // Оставить описание и категорию как null
  
  // TODO: Для Laptop:
  // - Вызвать displayProduct()
  // - Вывести "Description length: [length]", используя getDescriptionLength()
  // - Вывести "Category: [uppercase]", используя getCategoryUppercase()
  
  // TODO: Для Mystery Item:
  // - Вызвать displayProduct()
  // - Вывести "Description length: [length]", используя getDescriptionLength()
}
quiz iconПроверьте себя

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

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