Можно ли использовать late и final вместе?

Я пробую NNBD на данный момент и хотел бы знать, можете ли вы использовать новое ключевое слово late и final все вместе.

Насколько я понял, lateСвойство можно установить где угодно. По сути, вы говорите анализатору, что он не будет нулевым при использовании.
Я думаю, что в некоторых ситуациях это довольно опасно.

Мне интересно, можете ли вы добавить late final в NNBD это сообщит анализатору, что свойство должно быть инициализировано в конструкторе класса.

Есть аналогичный вопрос, но я думаю, что в то время не было нулевой безопасности: Dart. Поздняя инициализация конечных переменных

3 ответа

Вы можете объявить late final переменная.

Если вы объявите это с помощью инициализатора, late final foo = computeSomething();, то это ленивая конечная переменная. Вы не можете присвоить переменной, но ее значение вычисляется только при первом чтении переменной. (По моему опыту, это никогда не бывает правильным выбором для локальных переменных, даже если язык это позволяет. Если вам нужна отложенная инициализация локальной переменной, вы также почти всегда хотите знать , была ли она инициализирована, а ленивая переменная не не сообщаю вам эту информацию. Также сбивает с толку то, что код выполняется не по порядку, и он не позволяет вам использовать await в выражении инициализатора).

Если вы объявите late finalпеременная без инициализатора, вы можете записать в переменную один раз. Поскольку переменная late, компилятор не будет жаловаться на назначения во время компиляции, если не будет абсолютно уверен, что вы уже назначили переменную, и только если это локальная переменная (потому что это единственные переменные, которым компилятор пытается отслеживать назначения).

Если late finalпеременная без инициализатора является членом экземпляра класса, это означает, что интерфейс класса имеет сеттер. Вы должны быть очень и очень осторожны при обнаружении late finalпеременные в публичном API класса. (Читайте: не делайте этого!)

Лучше использовать поздние переменные внутри и защищать доступ к полям, чтобы вы могли гарантировать, что никто не назначит переменную дважды. Целью переменной позднего финала не является выброс, если она назначена дважды. Его нельзя назначать дважды. Это позволяет разрешить код, который по какой-то причине знает, что компилятор не может понять, что переменная назначается только один раз. Итак, разрешите доступ к переменным позднего финала только коду, который знает об этой причине и поддерживает инвариант.

Краткий ответ: Нет, вам не поможет анализатор.


Из спецификации языка nnbd:

Ошибка, если переменная верхнего уровня или статическая переменная с типом, не допускающим значения NULL, не имеет выражения инициализатора, если переменная не помечена с помощью позднего или внешнего модификатора.

Это ошибка, если объявление класса объявляет переменную экземпляра с потенциально не допускающим значения NULL типом и без выражения инициализатора, а в классе есть генеративный конструктор, в котором переменная не инициализируется с помощью формального инициализатора или записи списка инициализаторов, если только переменная помечен модификатором late, abstract или external.

late final int foo; в основном отключает нулевую осведомленность для foo. Это похоже на использование неявно развернутых опций в Swift, что может быть опасным, если вы знакомы с этим.

https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md

Кроме того, статический анализатор не предупреждает о попытках сбросить late final.

Пусть D будет late и final объявление локальной переменной с именем v. Это ошибка времени выполнения, вызывающая экземпляр LateInitializationError, чтобы присвоить значение v если значение было ранее присвоено v.

https://github.com/dart-lang/language/blob/master/accepted/future-releases/nnbd/feature-specification.md#late-fields-and-variables

С помощью late означает, что вам нужно точно знать, когда что-то инициализируется и используется.

Да!

Вы можете увидеть этот шаблон, который обычно используется при инициализации AnimationController.

      class _MyState extends State<MyPage> with SingleTickerProviderStateMixin {
  late final AnimationController _controller;

  @override
  void initState() {
    super.initState();
    _controller = AnimationController(vsync: this);
  }
}

И вы можете использовать его для ленивой инициализации, например:

      class Foo {
  late final int i = calculate; // Initialized only when used.

  int get calculate => ...;
}
Другие вопросы по тегам