Что такое null safety в Dart?

Ответ

Null safety — это набор функций языка Dart, который делает типы не nullable по умолчанию. Это означает, что переменная не может содержать null, если вы явно не разрешите это. Цель — устранить ошибки времени выполнения, связанные с разыменованием null (Null Pointer Exceptions), на этапе компиляции.

Ключевые концепции:

  1. Non-nullable по умолчанию: String name = 'Alex';name никогда не может быть null.
  2. Nullable типы: Чтобы разрешить null, используется ?. String? nickname;nickname может быть строкой или null.
  3. Обязательная инициализация: Non-nullable переменные должны быть инициализированы до использования.

Операторы для работы с nullable-переменными:

  • ?. (Опциональный доступ): Вызывает метод или получает свойство только если объект не null.
    String? maybeText;
    int? length = maybeText?.length; // length будет null, если maybeText null
  • ?? (Оператор если-null): Предоставляет значение по умолчанию.
    String displayName = nickname ?? 'Гость';
  • ! (Оператор утверждения не-null): Говорит компилятору: "Я уверен, что это значение не null сейчас". Использовать с осторожностью, так как при ошибке вызовет исключение во время выполнения.
    String definitelyText = maybeText!; // Runtime error, если maybeText null
  • late: Откладывает инициализацию non-nullable переменной. Вы обещаете присвоить значение до первого использования.
    late String apiKey;
    void init() {
      apiKey = fetchKeyFromConfig(); // Инициализируем позже
    }

Практический эффект: Код становится более предсказуемым, а анализ потока данных (flow analysis) компилятора помогает "видеть", когда nullable-переменная в определенной точке кода гарантированно не является null, позволяя использовать ее без лишних проверок.

Ответ 18+ 🔞

Э, слушай, ну это ж просто ёперный театр какой-то! Ну вот смотри, есть в языке Dart такая штука — null safety. Это, блядь, такая система, которая по умолчанию считает, что у тебя в переменных не может быть этой ебучей пустоты, этого null. То есть, если ты написал String name = 'Вася';, то name — это всегда строка, а не какая-то хитрая жопа, которая может внезапно оказаться ничем. Цель-то простая — чтобы твоя программа не накрылась медным тазом в самый неподходящий момент с криком "Null Pointer Exception, сука!". Всё ловят ещё на этапе компиляции, красота же!

Основные приколы, которые надо понять:

  1. По умолчанию — не пустота. String title = 'Заголовок'; — вот title нихуя не может стать null. Вообще. Попробуй присвоить — компилятор тебе такую пиздюлину влепит, мало не покажется.
  2. А если очень хочется пустоты? Тогда надо явно попросить, поставив вопросик ?. String? comment; — вот тут comment может быть или нормальной строкой, или этим самым null. Подозрение, блядь, чувствую к таким переменным.
  3. С инициализацией строго. Если переменная не может быть null, ты должен её сразу чем-то заполнить. Не инициализировал — опять получишь втык от компилятора. Доверия к тебе, блядь, ноль.

Ну и куда же без своих специальных палочек-выручалочек:

  • ?. (Опциональный доступ, он же "на всякий пожарный"): Ты как бы говоришь: "Э, объект, если ты не null — дай мне своё свойство, а если ты null — иди нахуй, я сам null и верну".
    String? maybeText;
    int? length = maybeText?.length; // Если maybeText пустой, то и length станет null, без скандала.
  • ?? (Оператор "или дай по умолчанию"): Классика! "Дай мне то, что слева, но если там null — дай то, что справа". Спасение для интерфейсов.
    String displayName = nickname ?? 'Анонимный герой';
  • ! (Оператор "я уверен, ёпта!"): Вот это опасная штука. Ты вручную выключаешь защиту и говоришь компилятору: "Отстань, я знаю, что тут не null!". Если соврал — будет тебе хиросима в рантайме. Пользоваться как острым ножом: вилкой в глаз или в жопу раз.
    String definitelyText = maybeText!; // Runtime error и слезы, если maybeText всё-таки null.
  • late (Ключевое слово "пообещал и сделаю"): Отмазка для ленивых. Говоришь компилятору: "Чувак, я эту non-nullable переменную проинициализирую, честно-честно, но попозже". Даёшь честное пионерское. Обманешь — получишь ошибку.
    late String apiKey;
    void init() {
      apiKey = fetchKeyFromConfig(); // Инициализирую, как обещал!
    }

А в итоге что? А в итоге код становится предсказуемым, как синьор помидор. Компилятор умнеет и начинает сам понимать, где переменная уже точно не null (после проверки, например), и позволяет тебе использовать её без этих ебушки-воробушки с вечными вопросиками. Удобно, чё.