Что такое оператор ??= в Dart
Что проверяют
Знаете ли вы null safety в Dart и понимаете ли, что перед вами составное присваивание с ленивой правой частью, а не общий оператор «подставь значение по умолчанию». Вопрос дешёвый, поэтому ценится точность: что именно считается пустым и когда вычисляется правый операнд.
Как отвечать
a ??= b присваивает b только если a сейчас равно null. Если значение уже есть, присваивания не происходит и правая часть вообще не вычисляется.
String? label;
label ??= buildLabel(); // buildLabel() не вызовется, если label уже заданКлючевые уточнения, которые стоит проговорить:
- условие ровно одно: равенство
null. Пустая строка, ноль иfalseостаются на месте, в отличие от привычного по JavaScript||=, который смотрит на ложность значения; - запись короче, чем
a = a ?? b, и обращение к цели происходит один раз, что важно для выражений с побочными эффектами; - работает и с элементами коллекций:
cache[key] ??= expensive()заполняет ключ только при отсутствующем значении; - переменная должна быть nullable. Для необнуляемого типа анализатор предупредит, что условие никогда не выполнится;
- рядом стоит семейство null-aware операций:
??,?., каскад?.., а для отложенной инициализации поля естьlate.
Где спотыкаются
Переносят привычку из JavaScript и ждут срабатывания на пустой строке. В интерфейсе появляется пустой заголовок вместо подстановки по умолчанию, и ошибка живёт до первого пользователя, который очистил поле.
Пытаются применить к полю с модификатором late final. Если оно уже инициализировано, повторное присваивание падает в рантайме, а если нет, чтение внутри проверки само по себе бросает ошибку.
Забывают про Map, где хранящееся значение null неотличимо от отсутствующего ключа: ??= его перезапишет, и логика «ключ уже обработан, значение пустое» тихо ломается.