Dart: Нулевая безопасность и извлечение значений из карт

#flutter #dart #types #dart-null-safety

Вопрос:

есть одна вещь, которую я не могу понять относительно нулевой безопасности в Dart, и это касается того, как безопасно извлекать значения из Map<String,dynamic> (я прочитал FAQ из документов Dart).

В принципе, следующий код в дартпаде с включенной защитой от ошибок действителен:

 void main() {
  int i;
  Map<String, dynamic> map = {"key": 1};
  i = map["key"];
  print(i);
}
 

Чего я не понимаю. Почему я могу назначить map["key"] , чтобы i компилятор не кричал на меня? Из документов:

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

Но именно это и происходит. Если в приведенном выше коде ключа нет на карте или он содержит какой-либо случайный тип, программа выйдет из строя во время выполнения, что, по-моему, никогда не должно происходить с нулевой безопасностью.

Меня это особенно интересует, так как я пишу приложение Flutter и не понимаю, как правильно десериализовать данные JSON, которые я получаю из БД ( try..catch ? Специальный синтаксис, например ??= ?). Несмотря на то, что у меня не включена функция «ненулевого» языка (я даже не могу писать int? val , не получив предупреждения), компилятор, похоже, не возражает против того, что я присваиваю ненулевые значения ненулевым переменным, и с радостью завершит работу во время выполнения, если они будут равны нулю.

В принципе, мой вопрос касается не только нулевой безопасности, но и системы типов в целом, поскольку, насколько я понимаю, не должно быть возможности присвоить dynamic значение int переменной, но, очевидно, это работает Map . Любое объяснение будет высоко оценено!

Комментарии:

1. У вас нет ошибки анализа, потому что у вас Map объявлены dynamic значения. Поэтому его operator [] отдача dynamic? такая же, как dynamic и . dynamic Тип отключает статическую проверку типов и полностью полагается на проверки во время выполнения. Если вам нужна правильная ошибка анализа, объявите свой Map с типом значения, не допускающим значения null (например Map<String, Object> ). (Возможно, анализатор должен распознать этот случай и настаивать на том, что i он все равно должен быть аннулирован, но я не знаю, возможно ли это на самом деле.)

2. Кроме того, если вы зададите implicit-casts: false в своем pubspec.yaml файле, вы должны получить ошибку анализа о dynamic int назначении кому. (Я думал, что неявные приведения были неявно отключены с нулевой безопасностью, но, возможно, есть какое-то исключение для неявных приведений dynamic .)

3. @jamesdlin За implicit-casts: false то , что вы ошибочно написали pubspec.yaml вместо analysis_options.yaml . Я думаю, что причина, по которой он не false находится в null-безопасном Dart, может заключаться в том, что даже если вы уверены, что данные из вашего json не являются нулевыми, вам придется использовать int? i = map['i']; и впоследствии обрабатывать это null . В некоторых случаях вам нужно такое поведение, а в некоторых-нет. Кстати, ваш первый комментарий заслуживает места в поле для ответов.

Ответ №1:

Динамическая переменная может содержать любой тип данных, ключевое слово «dynamic» используется, когда вы не знаете конкретный тип данных, который может быть возвращен.

и что ты на самом деле здесь делаешь:

i = карта[«ключ»];

присваивает «динамическую» переменную переменной «int», и поскольку в этом случае значение в паре ключ/значение вашей карты является целым числом, которое соответствует типу данных «int» переменной «i», оно не произойдет из-за вывода типа, выполненного во время выполнения, а не во время компиляции. если бы «динамическая» переменная была строкой, она бы вышла из строя во время выполнения из-за несоответствия типов. Надеюсь, это объяснимо.