weight
est un champ (Number in Firestore ), défini comme 100
.
int weight = json['weight'];
double weight = json['weight'];
int weight
fonctionne bien, renvoie 100
comme prévu, mais double weight
se bloque (Object.noSuchMethod
exception) plutôt que de renvoyer 100.0
, ce à quoi je m'attendais.
Cependant, les travaux suivants:
num weight = json['weight'];
num.toDouble();
Lors de l'analyse 100
de Firestore (qui ne supporte en fait pas un "type de nombre", mais le convertit ), il sera par défaut analysé en un int
.
Dart ne convertit pas automatiquement "intelligemment" ces types. En fait, vous ne pouvez pas convertir un int
en double
, ce qui est le problème auquel vous êtes confronté. Si c'était possible, votre code fonctionnerait très bien.
Au lieu de cela, vous pouvez analyser vous-même:
double weight = json['weight'].toDouble();
Ce qui fonctionne également, c'est d'analyser le JSON en num
puis de l'attribuer à un double
, qui convertira num
en double
.
double weight = json['weight'] as num;
Cela semble un peu étrange au début et en fait le outil d'analyse Dart (qui est par exemple intégré dans le plugin Dart pour VS Code et IntelliJ) le marquera comme un "distribution inutile" , ce qui n'est pas le cas.
double a = 100; // this will not compile
double b = 100 as num; // this will compile, but is still marked as an "unnecessary cast"
double b = 100 as num
compile parce que num
est la super classe de double
et Dart convertit super en sous-types même sans transtypages explicites.
Une conversion explicite serait la suivante:
double a = 100 as double; // does not compile because int is not the super class of double
double b = (100 as num) as double; // compiles, you can also omit the double cast
Voici une bonne lecture à propos de "Types et casting dans Dart".
Ce qui vous est arrivé est le suivant:
double weight;
weight = 100; // cannot compile because 100 is considered an int
// is the same as
weight = 100 as double; // which cannot work as I explained above
// Dart adds those casts automatically
Vous pouvez analyser les données comme indiqué ci-dessous:
Voici le document est un Map<String,dynamic>
double opening = double.tryParse(document['opening'].toString());
Vous pouvez le faire en une seule ligne:
double weight = (json['weight'] as num).toDouble();
Dans Dart, int
et double
sont des types distincts, les deux sous-types de num
.
Il n'y a pas de conversion automatique entre les types de numéros. Si vous écrivez:
num n = 100;
double d = n;
vous obtiendrez une erreur d'exécution. Le système de type statique de Dart autorise les rétrogradations non sécurisées, donc l'affectation non sécurisée de n
à d
(dangereuse car toutes les valeurs num
ne sont pas des valeurs double
) est traité implicitement comme:
num n = 100;
double d = n as double;
Le as double
vérifie que la valeur est bien un double
(ou null
), et lance si ce n'est pas le cas. Si cette vérification réussit, elle peut affecter la valeur à d
en toute sécurité car elle est connue pour correspondre au type de variable.
Voilà ce qui se passe ici. La valeur réelle de json['weight']
(Probablement avec le type statique Object
ou dynamic
) est l'objet int
avec la valeur 100. Affectant cela à int
travaux. L'affecter à num
fonctionne. L'affecter aux lancers double
.
L'analyseur Dart JSON analyse les nombres sous forme d'entiers s'ils n'ont pas de parties décimales ou exposantes (0.0
Est un double, 0e0
Est un double, 0
Est un entier). C'est très pratique dans la plupart des cas, mais parfois ennuyeux dans des cas comme le vôtre où vous voulez un double
, mais le code créant le JSON ne l'a pas écrit en double.
Dans de tels cas, il vous suffit d'écrire .toDouble()
sur les valeurs lorsque vous les extrayez. C'est un no-op sur les doubles réels.
En remarque, Dart compilé en JavaScript représente tous les nombres en tant que type de numéro JavaScript, ce qui signifie que tous les nombres sont doubles. Dans le code compilé JS, tous les entiers peuvent être affectés au double sans conversion. Cela fonctionnera pas lorsque le code est exécuté sur une implémentation non JS, comme Flutter, Dart VM/server ou une compilation anticipée pour iOS, alors ne dépendez pas de cela, ou de votre le code ne sera pas portable.